home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / kybd.c < prev    next >
C/C++ Source or Header  |  2009-02-26  |  70KB  |  3,239 lines

  1. /*
  2.  * Modifications Copyright 1993, 1994, 1995, 1996, 1999, 2000 by Paul Mattes.
  3.  * Original X11 Port Copyright 1990 by Jeff Sparkes.
  4.  *  Permission to use, copy, modify, and distribute this software and its
  5.  *  documentation for any purpose and without fee is hereby granted,
  6.  *  provided that the above copyright notice appear in all copies and that
  7.  *  both that copyright notice and this permission notice appear in
  8.  *  supporting documentation.
  9.  *
  10.  * Copyright 1989 by Georgia Tech Research Corporation, Atlanta, GA 30332.
  11.  *  All Rights Reserved.  GTRC hereby grants public use of this software.
  12.  *  Derivative works based on this software must incorporate this copyright
  13.  *  notice.
  14.  */
  15.  
  16. /*
  17.  *    kybd.c
  18.  *        This module handles the keyboard for the 3270 emulator.
  19.  */
  20.  
  21. #include "globals.h"
  22.  
  23. #if defined(X3270_DISPLAY) /*[*/
  24. #include <X11/Xatom.h>
  25. #endif
  26. #define XK_3270
  27. #if defined(X3270_APL) /*[*/
  28. #define XK_APL
  29. #endif /*]*/
  30. #include <X11/keysym.h>
  31.  
  32. #include <fcntl.h>
  33. #include "3270ds.h"
  34. #include "appres.h"
  35. #include "ctlr.h"
  36. #include "cg.h"
  37. #include "resources.h"
  38.  
  39. #include "actionsc.h"
  40. #include "ansic.h"
  41. #include "aplc.h"
  42. #include "ctlrc.h"
  43. #include "ftc.h"
  44. #include "hostc.h"
  45. #include "keymapc.h"
  46. #include "keypadc.h"
  47. #include "kybdc.h"
  48. #include "macrosc.h"
  49. #include "popupsc.h"
  50. #include "printc.h"
  51. #include "screenc.h"
  52. #if defined(X3270_DISPLAY) /*[*/
  53. #include "selectc.h"
  54. #endif /*]*/
  55. #include "statusc.h"
  56. #include "tablesc.h"
  57. #include "telnetc.h"
  58. #include "togglesc.h"
  59. #include "trace_dsc.h"
  60. #include "utilc.h"
  61.  
  62. /* Statics */
  63. static enum    { NONE, COMPOSE, FIRST } composing = NONE;
  64. static unsigned char pf_xlate[] = { 
  65.     AID_PF1,  AID_PF2,  AID_PF3,  AID_PF4,  AID_PF5,  AID_PF6,
  66.     AID_PF7,  AID_PF8,  AID_PF9,  AID_PF10, AID_PF11, AID_PF12,
  67.     AID_PF13, AID_PF14, AID_PF15, AID_PF16, AID_PF17, AID_PF18,
  68.     AID_PF19, AID_PF20, AID_PF21, AID_PF22, AID_PF23, AID_PF24
  69. };
  70. static unsigned char pa_xlate[] = { 
  71.     AID_PA1, AID_PA2, AID_PA3
  72. };
  73. #define PF_SZ    (sizeof(pf_xlate)/sizeof(pf_xlate[0]))
  74. #define PA_SZ    (sizeof(pa_xlate)/sizeof(pa_xlate[0]))
  75. static unsigned long unlock_id;
  76. #define UNLOCK_MS    350
  77. static Boolean key_Character(int cgcode, Boolean with_ge, Boolean pasting);
  78. static Boolean flush_ta(void);
  79. static void key_AID(unsigned char aid_code);
  80. static void kybdlock_set(unsigned int bits, const char *cause);
  81. static KeySym MyStringToKeysym(char *s, enum keytype *keytypep);
  82.  
  83. static int nxk = 0;
  84. static struct xks {
  85.     KeySym key;
  86.     KeySym assoc;
  87. } *xk;
  88.  
  89. static Boolean        insert = False;        /* insert mode */
  90. static Boolean        reverse = False;    /* reverse-input mode */
  91.  
  92. /* Globals */
  93. unsigned int    kybdlock = KL_NOT_CONNECTED;
  94. unsigned char    aid = AID_NO;        /* current attention ID */
  95.  
  96. /* Composite key mappings. */
  97.  
  98. struct akeysym {
  99.     KeySym keysym;
  100.     enum keytype keytype;
  101. };
  102. static struct akeysym cc_first;
  103. static struct composite {
  104.     struct akeysym k1, k2;
  105.     struct akeysym translation;
  106. } *composites = NULL;
  107. static int n_composites = 0;
  108.  
  109. #define ak_eq(k1, k2)    (((k1).keysym  == (k2).keysym) && \
  110.              ((k1).keytype == (k2).keytype))
  111.  
  112. static struct ta {
  113.     struct ta *next;
  114.     XtActionProc fn;
  115.     char *parm1;
  116.     char *parm2;
  117. } *ta_head = (struct ta *) NULL,
  118.   *ta_tail = (struct ta *) NULL;
  119.  
  120. static char dxl[] = "0123456789abcdef";
  121. #define FROM_HEX(c)    (strchr(dxl, tolower(c)) - dxl)
  122.  
  123. extern Widget *screen;
  124.  
  125.  
  126. /*
  127.  * Put an action on the typeahead queue.
  128.  */
  129. static void
  130. enq_ta(XtActionProc fn, char *parm1, char *parm2)
  131. {
  132.     struct ta *ta;
  133.  
  134.     /* If no connection, forget it. */
  135.     if (!CONNECTED) {
  136.         trace_event("  dropped (not connected)\n");
  137.         return;
  138.     }
  139.  
  140.     /* If operator error, complain and drop it. */
  141.     if (kybdlock & KL_OERR_MASK) {
  142.         ring_bell();
  143.         trace_event("  dropped (operator error)\n");
  144.         return;
  145.     }
  146.  
  147.     /* If scroll lock, complain and drop it. */
  148.     if (kybdlock & KL_SCROLLED) {
  149.         ring_bell();
  150.         trace_event("  dropped (scrolled)\n");
  151.         return;
  152.     }
  153.  
  154.     /* If typeahead disabled, complain and drop it. */
  155.     if (!appres.typeahead) {
  156.         trace_event("  dropped (no typeahead)\n");
  157.         return;
  158.     }
  159.  
  160.     ta = (struct ta *) Malloc(sizeof(*ta));
  161.     ta->next = (struct ta *) NULL;
  162.     ta->fn = fn;
  163.     ta->parm1 = ta->parm2 = CN;
  164.     if (parm1) {
  165.         ta->parm1 = NewString(parm1);
  166.         if (parm2)
  167.             ta->parm2 = NewString(parm2);
  168.     }
  169.     if (ta_head)
  170.         ta_tail->next = ta;
  171.     else {
  172.         ta_head = ta;
  173.         status_typeahead(True);
  174.     }
  175.     ta_tail = ta;
  176.  
  177.     trace_event("  action queued (kybdlock 0x%x)\n", kybdlock);
  178. }
  179.  
  180. /*
  181.  * Execute an action from the typeahead queue.
  182.  */
  183. Boolean
  184. run_ta(void)
  185. {
  186.     struct ta *ta;
  187.  
  188.     if (kybdlock || (ta = ta_head) == (struct ta *)NULL)
  189.         return False;
  190.  
  191.     if ((ta_head = ta->next) == (struct ta *)NULL) {
  192.         ta_tail = (struct ta *)NULL;
  193.         status_typeahead(False);
  194.     }
  195.  
  196.     action_internal(ta->fn, IA_TYPEAHEAD, ta->parm1, ta->parm2);
  197.     if (ta->parm1 != CN)
  198.         Free(ta->parm1);
  199.     if (ta->parm2 != CN)
  200.         Free(ta->parm2);
  201.     Free(ta);
  202.  
  203.     return True;
  204. }
  205.  
  206. /*
  207.  * Flush the typeahead queue.
  208.  * Returns whether or not anything was flushed.
  209.  */
  210. static Boolean
  211. flush_ta(void)
  212. {
  213.     struct ta *ta, *next;
  214.     Boolean any = False;
  215.  
  216.     for (ta = ta_head; ta != (struct ta *) NULL; ta = next) {
  217.         if (ta->parm1)
  218.             Free(ta->parm1);
  219.         if (ta->parm2)
  220.             Free(ta->parm2);
  221.         next = ta->next;
  222.         Free(ta);
  223.         any = True;
  224.     }
  225.     ta_head = ta_tail = (struct ta *) NULL;
  226.     status_typeahead(False);
  227.     return any;
  228. }
  229.  
  230. /* Set bits in the keyboard lock. */
  231. static void
  232. kybdlock_set(unsigned int bits, const char *cause unused)
  233. {
  234.     unsigned int n;
  235.  
  236.     n = kybdlock | bits;
  237.     if (n != kybdlock) {
  238. #if defined(KYBDLOCK_TRACE) /*[*/
  239.            trace_event("  %s: kybdlock |= 0x%04x, 0x%04x -> 0x%04x\n",
  240.             cause, bits, kybdlock, n);
  241. #endif /*]*/
  242.         kybdlock = n;
  243.         status_kybdlock();
  244.     }
  245. }
  246.  
  247. /* Clear bits in the keyboard lock. */
  248. void
  249. kybdlock_clr(unsigned int bits, const char *cause unused)
  250. {
  251.     unsigned int n;
  252.  
  253.     n = kybdlock & ~bits;
  254.     if (n != kybdlock) {
  255. #if defined(KYBDLOCK_TRACE) /*[*/
  256.         trace_event("  %s: kybdlock &= ~0x%04x, 0x%04x -> 0x%04x\n",
  257.             cause, bits, kybdlock, n);
  258. #endif /*]*/
  259.         kybdlock = n;
  260.         status_kybdlock();
  261.     }
  262. }
  263.  
  264. /*
  265.  * Set or clear enter-inhibit mode.
  266.  */
  267. void
  268. kybd_inhibit(Boolean inhibit)
  269. {
  270.     if (inhibit) {
  271.         kybdlock_set(KL_ENTER_INHIBIT, "kybd_inhibit");
  272.         if (kybdlock == KL_ENTER_INHIBIT)
  273.             status_reset();
  274.     } else {
  275.         kybdlock_clr(KL_ENTER_INHIBIT, "kybd_inhibit");
  276.         if (!kybdlock)
  277.             status_reset();
  278.     }
  279. }
  280.  
  281. /*
  282.  * Called when a host connects or disconnects.
  283.  */
  284. static void
  285. kybd_connect(Boolean connected)
  286. {
  287.     if (kybdlock & KL_DEFERRED_UNLOCK)
  288.         RemoveTimeOut(unlock_id);
  289.     kybdlock_clr(-1, "kybd_connect");
  290.  
  291.     if (connected) {
  292.         /* Wait for any output or a WCC(restore) from the host */
  293.         kybdlock_set(KL_AWAITING_FIRST, "kybd_connect");
  294.     } else {
  295.         kybdlock_set(KL_NOT_CONNECTED, "kybd_connect");
  296.         (void) flush_ta();
  297.     }
  298. }
  299.  
  300. /*
  301.  * Called when we switch between 3270 and ANSI modes.
  302.  */
  303. static void
  304. kybd_in3270(Boolean in3270 unused)
  305. {
  306.     if (kybdlock & KL_DEFERRED_UNLOCK)
  307.         RemoveTimeOut(unlock_id);
  308.     kybdlock_clr(-1, "kybd_connect");
  309. }
  310.  
  311. /*
  312.  * Called to initialize the keyboard logic.
  313.  */
  314. void
  315. kybd_init(void)
  316. {
  317.     /* Register interest in connect and disconnect events. */
  318.     register_schange(ST_CONNECT, kybd_connect);
  319.     register_schange(ST_3270_MODE, kybd_in3270);
  320. }
  321.  
  322. /*
  323.  * Toggle insert mode.
  324.  */
  325. static void
  326. insert_mode(Boolean on)
  327. {
  328.     insert = on;
  329.     status_insert_mode(on);
  330. }
  331.  
  332. /*
  333.  * Toggle reverse mode.
  334.  */
  335. static void
  336. reverse_mode(Boolean on)
  337. {
  338.     reverse = on;
  339.     status_reverse_mode(on);
  340. }
  341.  
  342. /*
  343.  * Lock the keyboard because of an operator error.
  344.  */
  345. static void
  346. operator_error(int error_type)
  347. {
  348.     if (sms_redirect())
  349.         popup_an_error("Keyboard locked");
  350.     if (appres.oerr_lock || sms_redirect()) {
  351.         status_oerr(error_type);
  352.         mcursor_locked();
  353.         kybdlock_set((unsigned int)error_type, "operator_error");
  354.         (void) flush_ta();
  355.     } else {
  356.         ring_bell();
  357.     }
  358. }
  359.  
  360.  
  361. /*
  362.  * Handle an AID (Attention IDentifier) key.  This is the common stuff that
  363.  * gets executed for all AID keys (PFs, PAs, Clear and etc).
  364.  */
  365. static void
  366. key_AID(unsigned char aid_code)
  367. {
  368. #if defined(X3270_ANSI) /*[*/
  369.     if (IN_ANSI) {
  370.         register unsigned i;
  371.  
  372.         if (aid_code == AID_ENTER) {
  373.             net_sendc('\r');
  374.             return;
  375.         }
  376.         for (i = 0; i < PF_SZ; i++)
  377.             if (aid_code == pf_xlate[i]) {
  378.                 ansi_send_pf(i+1);
  379.                 return;
  380.             }
  381.         for (i = 0; i < PA_SZ; i++)
  382.             if (aid_code == pa_xlate[i]) {
  383.                 ansi_send_pa(i+1);
  384.                 return;
  385.             }
  386.         return;
  387.     }
  388. #endif /*]*/
  389.     if (IN_SSCP) {
  390.         if (kybdlock & KL_OIA_MINUS)
  391.             return;
  392.         if (aid_code != AID_ENTER && aid_code != AID_CLEAR) {
  393.             status_minus();
  394.             kybdlock_set(KL_OIA_MINUS, "key_AID");
  395.             return;
  396.         }
  397.     }
  398.     if (IN_SSCP && aid_code == AID_ENTER) {
  399.         /* Act as if the host had written our input. */
  400.         buffer_addr = cursor_addr;
  401.     }
  402.     if (!IN_SSCP || aid_code != AID_CLEAR) {
  403.         status_twait();
  404.         mcursor_waiting();
  405.         insert_mode(False);
  406.         kybdlock_set(KL_OIA_TWAIT | KL_OIA_LOCKED, "key_AID");
  407.     }
  408.     aid = aid_code;
  409.     ctlr_read_modified(aid, False);
  410.     if (!IN_SSCP) {
  411.         ticking_start(False);
  412.         status_ctlr_done();
  413.     }
  414. }
  415.  
  416. void
  417. PF_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  418. {
  419.     unsigned k;
  420.  
  421.     action_debug(PF_action, event, params, num_params);
  422.     if (check_usage(PF_action, *num_params, 1, 1) < 0)
  423.         return;
  424.     k = atoi(params[0]);
  425.     if (k < 1 || k > PF_SZ) {
  426.         popup_an_error("%s: Invalid argument '%s'",
  427.             action_name(PF_action), params[0]);
  428.         return;
  429.     }
  430.     if (kybdlock & KL_OIA_MINUS)
  431.         return;
  432.     else if (kybdlock)
  433.         enq_ta(PF_action, params[0], CN);
  434.     else
  435.         key_AID(pf_xlate[k-1]);
  436. }
  437.  
  438. void
  439. PA_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  440. {
  441.     unsigned k;
  442.  
  443.     action_debug(PA_action, event, params, num_params);
  444.     if (check_usage(PA_action, *num_params, 1, 1) < 0)
  445.         return;
  446.     k = atoi(params[0]);
  447.     if (k < 1 || k > PA_SZ) {
  448.         popup_an_error("%s: Invalid argument '%s'",
  449.             action_name(PA_action), params[0]);
  450.         return;
  451.     }
  452.     if (kybdlock & KL_OIA_MINUS)
  453.         return;
  454.     else if (kybdlock)
  455.         enq_ta(PA_action, params[0], CN);
  456.     else
  457.         key_AID(pa_xlate[k-1]);
  458. }
  459.  
  460.  
  461. /*
  462.  * ATTN key, per RFC 2355.  Sends IP, regardless.
  463.  */
  464. void
  465. Attn_action(Widget w unused, XEvent *event, String *params,
  466.     Cardinal *num_params)
  467. {
  468.     action_debug(Attn_action, event, params, num_params);
  469.     if (!IN_3270)
  470.         return;
  471.     net_interrupt();
  472. }
  473.  
  474. /*
  475.  * IAC IP, which works for 5250 System Request and interrupts the program
  476.  * on an AS/400, even when the keyboard is locked.
  477.  *
  478.  * This is now the same as the Attn action.
  479.  */
  480. void
  481. Interrupt_action(Widget w unused, XEvent *event, String *params,
  482.     Cardinal *num_params)
  483. {
  484.     action_debug(Interrupt_action, event, params, num_params);
  485.     if (!IN_3270)
  486.         return;
  487.     net_interrupt();
  488. }
  489.  
  490.  
  491.  
  492. #define GE_WFLAG    0x100
  493. #define PASTE_WFLAG    0x200
  494.  
  495. static void
  496. key_Character_wrapper(Widget w unused, XEvent *event unused, String *params,
  497.     Cardinal *num_params unused)
  498. {
  499.     int cgcode;
  500.     Boolean with_ge = False;
  501.     Boolean pasting = False;
  502.  
  503.     cgcode = atoi(params[0]);
  504.     if (cgcode & GE_WFLAG) {
  505.         with_ge = True;
  506.         cgcode &= ~GE_WFLAG;
  507.     }
  508.     if (cgcode & PASTE_WFLAG) {
  509.         pasting = True;
  510.         cgcode &= ~PASTE_WFLAG;
  511.     }
  512.     trace_event(" %s -> Key(%s\"%s\")\n",
  513.         ia_name[(int) ia_cause],
  514.         with_ge ? "GE " : "",
  515.         ctl_see((int) cg2asc[cgcode]));
  516.     (void) key_Character(cgcode, with_ge, pasting);
  517. }
  518.  
  519. /*
  520.  * Handle an ordinary displayable character key.  Lots of stuff to handle
  521.  * insert-mode, protected fields and etc.
  522.  */
  523. static Boolean
  524. key_Character(int cgcode, Boolean with_ge, Boolean pasting)
  525. {
  526.     register int    baddr, end_baddr;
  527.     register unsigned char    *fa;
  528.     Boolean no_room = False;
  529.  
  530.     if (kybdlock) {
  531.         char code[64];
  532.  
  533.         (void) sprintf(code, "%d", cgcode |
  534.             (with_ge ? GE_WFLAG : 0) |
  535.             (pasting ? PASTE_WFLAG : 0));
  536.         enq_ta(key_Character_wrapper, code, CN);
  537.         return False;
  538.     }
  539.     baddr = cursor_addr;
  540.     fa = get_field_attribute(baddr);
  541.     if (IS_FA(screen_buf[baddr]) || FA_IS_PROTECTED(*fa)) {
  542.         operator_error(KL_OERR_PROTECTED);
  543.         return False;
  544.     }
  545.     if (appres.numeric_lock && FA_IS_NUMERIC(*fa) &&
  546.         !((cgcode >= CG_0 && cgcode <= CG_9) ||
  547.           cgcode == CG_minus || cgcode == CG_period)) {
  548.         operator_error(KL_OERR_NUMERIC);
  549.         return False;
  550.     }
  551.     if (reverse || (insert && screen_buf[baddr])) {
  552.         int last_blank = -1;
  553.  
  554.         /* Find next null, next fa, or last blank */
  555.         end_baddr = baddr;
  556.         if (screen_buf[end_baddr] == CG_space)
  557.             last_blank = end_baddr;
  558.         do {
  559.             INC_BA(end_baddr);
  560.             if (screen_buf[end_baddr] == CG_space)
  561.                 last_blank = end_baddr;
  562.             if (screen_buf[end_baddr] == CG_null
  563.                 ||  IS_FA(screen_buf[end_baddr]))
  564.                 break;
  565.         } while (end_baddr != baddr);
  566.  
  567.         /* Pretend a trailing blank is a null, if desired. */
  568.         if (toggled(BLANK_FILL) && last_blank != -1) {
  569.             INC_BA(last_blank);
  570.             if (last_blank == end_baddr) {
  571.                 DEC_BA(end_baddr);
  572.                 ctlr_add(end_baddr, CG_null, 0);
  573.             }
  574.         }
  575.  
  576.         /* Check for field overflow. */
  577.         if (screen_buf[end_baddr] != CG_null) {
  578.             if (insert) {
  579.                 operator_error(KL_OERR_OVERFLOW);
  580.                 return False;
  581.             } else {    /* reverse */
  582.                 no_room = True;
  583.             }
  584.         } else {
  585.             /* Shift data over. */
  586.             if (end_baddr > baddr) {
  587.                 /* At least one byte to copy, no wrap. */
  588.                 ctlr_bcopy(baddr, baddr+1, end_baddr - baddr,
  589.                     0);
  590.             } else if (end_baddr < baddr) {
  591.                 /* At least one byte to copy, wraps to top. */
  592.                 ctlr_bcopy(0, 1, end_baddr, 0);
  593.                 ctlr_add(0, screen_buf[(ROWS * COLS) - 1], 0);
  594.                 ctlr_bcopy(baddr, baddr+1,
  595.                     ((ROWS * COLS) - 1) - baddr, 0);
  596.             }
  597.         }
  598.  
  599.     }
  600.  
  601.     /* Replace leading nulls with blanks, if desired. */
  602.     if (formatted && toggled(BLANK_FILL)) {
  603.         int        baddr_sof = fa - screen_buf;
  604.         register int    baddr_fill = baddr;
  605.  
  606.         DEC_BA(baddr_fill);
  607.         while (baddr_fill != baddr_sof) {
  608.  
  609.             /* Check for backward line wrap. */
  610.             if ((baddr_fill % COLS) == COLS - 1) {
  611.                 Boolean aborted = True;
  612.                 register int baddr_scan = baddr_fill;
  613.  
  614.                 /*
  615.                  * Check the field within the preceeding line
  616.                  * for NULLs.
  617.                  */
  618.                 while (baddr_scan != baddr_sof) {
  619.                     if (screen_buf[baddr_scan] != CG_null) {
  620.                         aborted = False;
  621.                         break;
  622.                     }
  623.                     if (!(baddr_scan % COLS))
  624.                         break;
  625.                     DEC_BA(baddr_scan);
  626.                 }
  627.                 if (aborted)
  628.                     break;
  629.             }
  630.  
  631.             if (screen_buf[baddr_fill] == CG_null)
  632.                 ctlr_add(baddr_fill, CG_space, 0);
  633.             DEC_BA(baddr_fill);
  634.         }
  635.     }
  636.  
  637.     /* Add the character. */
  638.     if (no_room) {
  639.         do {
  640.             INC_BA(baddr);
  641.         } while (!IS_FA(screen_buf[baddr]));
  642.     } else {
  643.         ctlr_add(baddr, (unsigned char)cgcode,
  644.             (unsigned char)(with_ge ? CS_GE : 0));
  645.         ctlr_add_fg(baddr, 0);
  646.         ctlr_add_gr(baddr, 0);
  647.         if (!reverse)
  648.             INC_BA(baddr);
  649.     }
  650.  
  651.     /*
  652.      * Implement auto-skip, and don't land on attribute bytes.
  653.      * This happens for all pasted data (even DUP), and for all
  654.      * keyboard-generated data except DUP.
  655.      */
  656.     if (pasting || (cgcode != CG_dup)) {
  657.         if (IS_FA(screen_buf[baddr]) &&
  658.             FA_IS_SKIP(screen_buf[baddr]))
  659.             baddr = next_unprotected(baddr);
  660.         else while (IS_FA(screen_buf[baddr]))
  661.             INC_BA(baddr);
  662.  
  663.         cursor_move(baddr);
  664.     }
  665.  
  666.     mdt_set(fa);
  667.     return True;
  668. }
  669.  
  670. /*
  671.  * Handle an ordinary character key, given an ASCII code.
  672.  */
  673. static void
  674. key_ACharacter(unsigned char c, enum keytype keytype, enum iaction cause)
  675. {
  676.     register int i;
  677.     struct akeysym ak;
  678.  
  679.     ak.keysym = c;
  680.     ak.keytype = keytype;
  681.  
  682.     switch (composing) {
  683.         case NONE:
  684.         break;
  685.         case COMPOSE:
  686.         for (i = 0; i < n_composites; i++)
  687.             if (ak_eq(composites[i].k1, ak) ||
  688.                 ak_eq(composites[i].k2, ak))
  689.                 break;
  690.         if (i < n_composites) {
  691.             cc_first.keysym = c;
  692.             cc_first.keytype = keytype;
  693.             composing = FIRST;
  694.             status_compose(True, c, keytype);
  695.         } else {
  696.             ring_bell();
  697.             composing = NONE;
  698.             status_compose(False, 0, KT_STD);
  699.         }
  700.         return;
  701.         case FIRST:
  702.         composing = NONE;
  703.         status_compose(False, 0, KT_STD);
  704.         for (i = 0; i < n_composites; i++)
  705.             if ((ak_eq(composites[i].k1, cc_first) &&
  706.                  ak_eq(composites[i].k2, ak)) ||
  707.                 (ak_eq(composites[i].k1, ak) &&
  708.                  ak_eq(composites[i].k2, cc_first)))
  709.                 break;
  710.         if (i < n_composites) {
  711.             c = composites[i].translation.keysym;
  712.             keytype = composites[i].translation.keytype;
  713.         } else {
  714.             ring_bell();
  715.             return;
  716.         }
  717.         break;
  718.     }
  719.  
  720.         trace_event(" %s -> Key(\"%s\")\n",
  721.             ia_name[(int) cause], ctl_see((int) c));
  722.     if (IN_3270) {
  723.         if (c < ' ') {
  724.             trace_event("  dropped (control char)\n");
  725.             return;
  726.         }
  727.         (void) key_Character((int) asc2cg[c], keytype == KT_GE, False);
  728.     }
  729. #if defined(X3270_ANSI) /*[*/
  730.     else if (IN_ANSI) {
  731.         net_sendc((char) c);
  732.     }
  733. #endif /*]*/
  734.     else {
  735.         trace_event("  dropped (not connected)\n");
  736.     }
  737. }
  738.  
  739.  
  740. /*
  741.  * Simple toggles.
  742.  */
  743. #if defined(X3270_DISPLAY) /*[*/
  744. void
  745. AltCursor_action(Widget w unused, XEvent *event, String *params,
  746.     Cardinal *num_params)
  747. {
  748.     action_debug(AltCursor_action, event, params, num_params);
  749.     do_toggle(ALT_CURSOR);
  750. }
  751. #endif /*]*/
  752.  
  753. void
  754. MonoCase_action(Widget w unused, XEvent *event, String *params,
  755.     Cardinal *num_params)
  756. {
  757.     action_debug(MonoCase_action, event, params, num_params);
  758.     do_toggle(MONOCASE);
  759. }
  760.  
  761. /*
  762.  * Flip the display left-to-right
  763.  */
  764. void
  765. Flip_action(Widget w unused, XEvent *event, String *params,
  766.     Cardinal *num_params)
  767. {
  768.     action_debug(Flip_action, event, params, num_params);
  769.     screen_flip();
  770. }
  771.  
  772.  
  773.  
  774. /*
  775.  * Tab forward to next field.
  776.  */
  777. void
  778. Tab_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  779. {
  780.     action_debug(Tab_action, event, params, num_params);
  781.     if (kybdlock) {
  782.         enq_ta(Tab_action, CN, CN);
  783.         return;
  784.     }
  785. #if defined(X3270_ANSI) /*[*/
  786.     if (IN_ANSI) {
  787.         net_sendc('\t');
  788.         return;
  789.     }
  790. #endif /*]*/
  791.     cursor_move(next_unprotected(cursor_addr));
  792. }
  793.  
  794.  
  795. /*
  796.  * Tab backward to previous field.
  797.  */
  798. void
  799. BackTab_action(Widget w unused, XEvent *event, String *params,
  800.     Cardinal *num_params)
  801. {
  802.     register int    baddr, nbaddr;
  803.     int        sbaddr;
  804.  
  805.     action_debug(BackTab_action, event, params, num_params);
  806.     if (kybdlock) {
  807.         enq_ta(BackTab_action, CN, CN);
  808.         return;
  809.     }
  810.     if (!IN_3270)
  811.         return;
  812.     baddr = cursor_addr;
  813.     DEC_BA(baddr);
  814.     if (IS_FA(screen_buf[baddr]))    /* at bof */
  815.         DEC_BA(baddr);
  816.     sbaddr = baddr;
  817.     while (True) {
  818.         nbaddr = baddr;
  819.         INC_BA(nbaddr);
  820.         if (IS_FA(screen_buf[baddr])
  821.             &&  !FA_IS_PROTECTED(screen_buf[baddr])
  822.             &&  !IS_FA(screen_buf[nbaddr]))
  823.             break;
  824.         DEC_BA(baddr);
  825.         if (baddr == sbaddr) {
  826.             cursor_move(0);
  827.             return;
  828.         }
  829.     }
  830.     INC_BA(baddr);
  831.     cursor_move(baddr);
  832. }
  833.  
  834.  
  835. /*
  836.  * Deferred keyboard unlock.
  837.  */
  838.  
  839. static void
  840. defer_unlock(void)
  841. {
  842.     kybdlock_clr(KL_DEFERRED_UNLOCK, "defer_unlock");
  843.     status_reset();
  844.     if (CONNECTED)
  845.         ps_process();
  846. }
  847.  
  848. /*
  849.  * Reset keyboard lock.
  850.  */
  851. void
  852. do_reset(Boolean explicit)
  853. {
  854.     /*
  855.      * If explicit (from the keyboard) and there is typeahead or
  856.      * a half-composed key, simply flush it.
  857.      */
  858.     if (explicit
  859. #if defined(X3270_FT) /*[*/
  860.         || ft_state != FT_NONE
  861. #endif /*]*/
  862.         ) {
  863.         Boolean half_reset = False;
  864.  
  865.         if (flush_ta())
  866.             half_reset = True;
  867.         if (composing != NONE) {
  868.             composing = NONE;
  869.             status_compose(False, 0, KT_STD);
  870.             half_reset = True;
  871.         }
  872.         if (half_reset)
  873.             return;
  874.     }
  875.  
  876.     /* Always clear insert mode. */
  877.     insert_mode(False);
  878.  
  879.     /* Otherwise, if not connect, reset is a no-op. */
  880.     if (!CONNECTED)
  881.         return;
  882.  
  883.     /*
  884.      * Remove any deferred keyboard unlock.  We will either unlock the
  885.      * keyboard now, or want to defer further into the future.
  886.      */
  887.     if (kybdlock & KL_DEFERRED_UNLOCK)
  888.         RemoveTimeOut(unlock_id);
  889.  
  890.     /*
  891.      * If explicit (from the keyboard), unlock the keyboard now.
  892.      * Otherwise (from the host), schedule a deferred keyboard unlock.
  893.      */
  894.     if (explicit) {
  895.         kybdlock_clr(-1, "do_reset");
  896.     } else if (kybdlock &
  897.   (KL_DEFERRED_UNLOCK | KL_OIA_TWAIT | KL_OIA_LOCKED | KL_AWAITING_FIRST)) {
  898.         kybdlock_clr(~KL_DEFERRED_UNLOCK, "do_reset");
  899.         kybdlock_set(KL_DEFERRED_UNLOCK, "do_reset");
  900.         unlock_id = AddTimeOut(UNLOCK_MS, defer_unlock);
  901.     }
  902.  
  903.     /* Clean up other modes. */
  904.     status_reset();
  905.     mcursor_normal();
  906.     composing = NONE;
  907.     status_compose(False, 0, KT_STD);
  908. }
  909.  
  910. void
  911. Reset_action(Widget w unused, XEvent *event, String *params,
  912.     Cardinal *num_params)
  913. {
  914.     action_debug(Reset_action, event, params, num_params);
  915.     do_reset(True);
  916. }
  917.  
  918.  
  919. /*
  920.  * Move to first unprotected field on screen.
  921.  */
  922. void
  923. Home_action(Widget w unused, XEvent *event, String *params,
  924.     Cardinal *num_params)
  925. {
  926.     action_debug(Home_action, event, params, num_params);
  927.     if (kybdlock) {
  928.         enq_ta(Home_action, CN, CN);
  929.         return;
  930.     }
  931. #if defined(X3270_ANSI) /*[*/
  932.     if (IN_ANSI) {
  933.         ansi_send_home();
  934.         return;
  935.     }
  936. #endif /*]*/
  937.     if (!formatted) {
  938.         cursor_move(0);
  939.         return;
  940.     }
  941.     cursor_move(next_unprotected(ROWS*COLS-1));
  942. }
  943.  
  944.  
  945. /*
  946.  * Cursor left 1 position.
  947.  */
  948. static void
  949. do_left(void)
  950. {
  951.     register int    baddr;
  952.  
  953.     baddr = cursor_addr;
  954.     DEC_BA(baddr);
  955.     cursor_move(baddr);
  956. }
  957.  
  958. void
  959. Left_action(Widget w unused, XEvent *event, String *params,
  960.     Cardinal *num_params)
  961. {
  962.     action_debug(Left_action, event, params, num_params);
  963.     if (kybdlock) {
  964.         enq_ta(Left_action, CN, CN);
  965.         return;
  966.     }
  967. #if defined(X3270_ANSI) /*[*/
  968.     if (IN_ANSI) {
  969.         ansi_send_left();
  970.         return;
  971.     }
  972. #endif /*]*/
  973.     if (!flipped)
  974.         do_left();
  975.     else {
  976.         register int    baddr;
  977.  
  978.         baddr = cursor_addr;
  979.         INC_BA(baddr);
  980.         cursor_move(baddr);
  981.     }
  982. }
  983.  
  984.  
  985. /*
  986.  * Delete char key.
  987.  * Returns "True" if succeeds, "False" otherwise.
  988.  */
  989. static Boolean
  990. do_delete(void)
  991. {
  992.     register int    baddr, end_baddr;
  993.     register unsigned char    *fa;
  994.  
  995.     baddr = cursor_addr;
  996.     fa = get_field_attribute(baddr);
  997.     if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
  998.         operator_error(KL_OERR_PROTECTED);
  999.         return False;
  1000.     }
  1001.     /* find next fa */
  1002.     end_baddr = baddr;
  1003.     do {
  1004.         INC_BA(end_baddr);
  1005.         if (IS_FA(screen_buf[end_baddr]))
  1006.             break;
  1007.     } while (end_baddr != baddr);
  1008.     DEC_BA(end_baddr);
  1009.     if (end_baddr > baddr) {
  1010.         ctlr_bcopy(baddr+1, baddr, end_baddr - baddr, 0);
  1011.     } else if (end_baddr != baddr) {
  1012.         ctlr_bcopy(baddr+1, baddr, ((ROWS * COLS) - 1) - baddr, 0);
  1013.         ctlr_add((ROWS * COLS) - 1, screen_buf[0], 0);
  1014.         ctlr_bcopy(1, 0, end_baddr, 0);
  1015.     }
  1016.     ctlr_add(end_baddr, CG_null, 0);
  1017.     mdt_set(fa);
  1018.     return True;
  1019. }
  1020.  
  1021. void
  1022. Delete_action(Widget w unused, XEvent *event, String *params,
  1023.     Cardinal *num_params)
  1024. {
  1025.     action_debug(Delete_action, event, params, num_params);
  1026.     if (kybdlock) {
  1027.         enq_ta(Delete_action, CN, CN);
  1028.         return;
  1029.     }
  1030. #if defined(X3270_ANSI) /*[*/
  1031.     if (IN_ANSI) {
  1032.         net_sendc('\177');
  1033.         return;
  1034.     }
  1035. #endif /*]*/
  1036.     if (!do_delete())
  1037.         return;
  1038.     if (reverse) {
  1039.         int baddr = cursor_addr;
  1040.  
  1041.         DEC_BA(baddr);
  1042.         if (!IS_FA(screen_buf[baddr]))
  1043.             cursor_move(baddr);
  1044.     }
  1045. }
  1046.  
  1047.  
  1048. /*
  1049.  * Backspace.
  1050.  */
  1051. void
  1052. BackSpace_action(Widget w unused, XEvent *event, String *params,
  1053.     Cardinal *num_params)
  1054. {
  1055.     action_debug(BackSpace_action, event, params, num_params);
  1056.     if (kybdlock) {
  1057.         enq_ta(BackSpace_action, CN, CN);
  1058.         return;
  1059.     }
  1060. #if defined(X3270_ANSI) /*[*/
  1061.     if (IN_ANSI) {
  1062.         net_send_erase();
  1063.         return;
  1064.     }
  1065. #endif /*]*/
  1066.     if (reverse)
  1067.         (void) do_delete();
  1068.     else if (!flipped)
  1069.         do_left();
  1070.     else {
  1071.         register int    baddr;
  1072.  
  1073.         baddr = cursor_addr;
  1074.         DEC_BA(baddr);
  1075.         cursor_move(baddr);
  1076.     }
  1077. }
  1078.  
  1079.  
  1080. /*
  1081.  * Destructive backspace, like Unix "erase".
  1082.  */
  1083. void
  1084. Erase_action(Widget w unused, XEvent *event, String *params,
  1085.     Cardinal *num_params)
  1086. {
  1087.     int    baddr;
  1088.     unsigned char    *fa;
  1089.  
  1090.     action_debug(Erase_action, event, params, num_params);
  1091.     if (kybdlock) {
  1092.         enq_ta(Erase_action, CN, CN);
  1093.         return;
  1094.     }
  1095. #if defined(X3270_ANSI) /*[*/
  1096.     if (IN_ANSI) {
  1097.         net_send_erase();
  1098.         return;
  1099.     }
  1100. #endif /*]*/
  1101.     baddr = cursor_addr;
  1102.     fa = get_field_attribute(baddr);
  1103.     if (fa == &screen_buf[baddr] || FA_IS_PROTECTED(*fa)) {
  1104.         operator_error(KL_OERR_PROTECTED);
  1105.         return;
  1106.     }
  1107.     if (baddr && fa == &screen_buf[baddr - 1])
  1108.         return;
  1109.     do_left();
  1110.     (void) do_delete();
  1111. }
  1112.  
  1113.  
  1114. /*
  1115.  * Cursor right 1 position.
  1116.  */
  1117. void
  1118. Right_action(Widget w unused, XEvent *event, String *params,
  1119.     Cardinal *num_params)
  1120. {
  1121.     register int    baddr;
  1122.  
  1123.     action_debug(Right_action, event, params, num_params);
  1124.     if (kybdlock) {
  1125.         enq_ta(Right_action, CN, CN);
  1126.         return;
  1127.     }
  1128. #if defined(X3270_ANSI) /*[*/
  1129.     if (IN_ANSI) {
  1130.         ansi_send_right();
  1131.         return;
  1132.     }
  1133. #endif /*]*/
  1134.     if (!flipped) {
  1135.         baddr = cursor_addr;
  1136.         INC_BA(baddr);
  1137.         cursor_move(baddr);
  1138.     } else
  1139.         do_left();
  1140. }
  1141.  
  1142.  
  1143. /*
  1144.  * Cursor left 2 positions.
  1145.  */
  1146. void
  1147. Left2_action(Widget w unused, XEvent *event, String *params,
  1148.     Cardinal *num_params)
  1149. {
  1150.     register int    baddr;
  1151.  
  1152.     action_debug(Left2_action, event, params, num_params);
  1153.     if (kybdlock) {
  1154.         enq_ta(Left2_action, CN, CN);
  1155.         return;
  1156.     }
  1157. #if defined(X3270_ANSI) /*[*/
  1158.     if (IN_ANSI)
  1159.         return;
  1160. #endif /*]*/
  1161.     baddr = cursor_addr;
  1162.     DEC_BA(baddr);
  1163.     DEC_BA(baddr);
  1164.     cursor_move(baddr);
  1165. }
  1166.  
  1167.  
  1168. /*
  1169.  * Cursor to previous word.
  1170.  */
  1171. void
  1172. PreviousWord_action(Widget w unused, XEvent *event, String *params,
  1173.     Cardinal *num_params)
  1174. {
  1175.     register int baddr;
  1176.     int baddr0;
  1177.     unsigned char  c;
  1178.     Boolean prot;
  1179.  
  1180.     action_debug(PreviousWord_action, event, params, num_params);
  1181.     if (kybdlock) {
  1182.         enq_ta(PreviousWord_action, CN, CN);
  1183.         return;
  1184.     }
  1185. #if defined(X3270_ANSI) /*[*/
  1186.     if (IN_ANSI)
  1187.         return;
  1188. #endif /*]*/
  1189.     if (!formatted)
  1190.         return;
  1191.  
  1192.     baddr = cursor_addr;
  1193.     prot = FA_IS_PROTECTED(*get_field_attribute(baddr));
  1194.  
  1195.     /* Skip to before this word, if in one now. */
  1196.     if (!prot) {
  1197.         c = screen_buf[baddr];
  1198.         while (!IS_FA(c) && c != CG_space && c != CG_null) {
  1199.             DEC_BA(baddr);
  1200.             if (baddr == cursor_addr)
  1201.                 return;
  1202.             c = screen_buf[baddr];
  1203.         }
  1204.     }
  1205.     baddr0 = baddr;
  1206.  
  1207.     /* Find the end of the preceding word. */
  1208.     do {
  1209.         c = screen_buf[baddr];
  1210.         if (IS_FA(c)) {
  1211.             DEC_BA(baddr);
  1212.             prot = FA_IS_PROTECTED(*get_field_attribute(baddr));
  1213.             continue;
  1214.         }
  1215.         if (!prot && c != CG_space && c != CG_null)
  1216.             break;
  1217.         DEC_BA(baddr);
  1218.     } while (baddr != baddr0);
  1219.  
  1220.     if (baddr == baddr0)
  1221.         return;
  1222.  
  1223.     /* Go it its front. */
  1224.     for (;;) {
  1225.         DEC_BA(baddr);
  1226.         c = screen_buf[baddr];
  1227.         if (IS_FA(c) || c == CG_space || c == CG_null) {
  1228.             break;
  1229.         }
  1230.     }
  1231.     INC_BA(baddr);
  1232.     cursor_move(baddr);
  1233. }
  1234.  
  1235.  
  1236. /*
  1237.  * Cursor right 2 positions.
  1238.  */
  1239. void
  1240. Right2_action(Widget w unused, XEvent *event, String *params,
  1241.     Cardinal *num_params)
  1242. {
  1243.     register int    baddr;
  1244.  
  1245.     action_debug(Right2_action, event, params, num_params);
  1246.     if (kybdlock) {
  1247.         enq_ta(Right2_action, CN, CN);
  1248.         return;
  1249.     }
  1250. #if defined(X3270_ANSI) /*[*/
  1251.     if (IN_ANSI)
  1252.         return;
  1253. #endif /*]*/
  1254.     baddr = cursor_addr;
  1255.     INC_BA(baddr);
  1256.     INC_BA(baddr);
  1257.     cursor_move(baddr);
  1258. }
  1259.  
  1260.  
  1261. /* Find the next unprotected word, or -1 */
  1262. static int
  1263. nu_word(int baddr)
  1264. {
  1265.     int baddr0 = baddr;
  1266.     unsigned char c;
  1267.     Boolean prot;
  1268.  
  1269.     prot = FA_IS_PROTECTED(*get_field_attribute(baddr));
  1270.  
  1271.     do {
  1272.         c = screen_buf[baddr];
  1273.         if (IS_FA(c))
  1274.             prot = FA_IS_PROTECTED(c);
  1275.         else if (!prot && c != CG_space && c != CG_null)
  1276.             return baddr;
  1277.         INC_BA(baddr);
  1278.     } while (baddr != baddr0);
  1279.  
  1280.     return -1;
  1281. }
  1282.  
  1283. /* Find the next word in this field, or -1 */
  1284. static int
  1285. nt_word(int baddr)
  1286. {
  1287.     int baddr0 = baddr;
  1288.     unsigned char c;
  1289.     Boolean in_word = True;
  1290.  
  1291.     do {
  1292.         c = screen_buf[baddr];
  1293.         if (IS_FA(c))
  1294.             return -1;
  1295.         if (in_word) {
  1296.             if (c == CG_space || c == CG_null)
  1297.                 in_word = False;
  1298.         } else {
  1299.             if (c != CG_space && c != CG_null)
  1300.                 return baddr;
  1301.         }
  1302.         INC_BA(baddr);
  1303.     } while (baddr != baddr0);
  1304.  
  1305.     return -1;
  1306. }
  1307.  
  1308.  
  1309. /*
  1310.  * Cursor to next unprotected word.
  1311.  */
  1312. void
  1313. NextWord_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1314. {
  1315.     register int    baddr;
  1316.     unsigned char c;
  1317.  
  1318.     action_debug(NextWord_action, event, params, num_params);
  1319.     if (kybdlock) {
  1320.         enq_ta(NextWord_action, CN, CN);
  1321.         return;
  1322.     }
  1323. #if defined(X3270_ANSI) /*[*/
  1324.     if (IN_ANSI)
  1325.         return;
  1326. #endif /*]*/
  1327.     if (!formatted)
  1328.         return;
  1329.  
  1330.     /* If not in an unprotected field, go to the next unprotected word. */
  1331.     if (IS_FA(screen_buf[cursor_addr]) ||
  1332.         FA_IS_PROTECTED(*get_field_attribute(cursor_addr))) {
  1333.         baddr = nu_word(cursor_addr);
  1334.         if (baddr != -1)
  1335.             cursor_move(baddr);
  1336.         return;
  1337.     }
  1338.  
  1339.     /* If there's another word in this field, go to it. */
  1340.     baddr = nt_word(cursor_addr);
  1341.     if (baddr != -1) {
  1342.         cursor_move(baddr);
  1343.         return;
  1344.     }
  1345.  
  1346.     /* If in a word, go to just after its end. */
  1347.     c = screen_buf[cursor_addr];
  1348.     if (c != CG_space && c != CG_null) {
  1349.         baddr = cursor_addr;
  1350.         do {
  1351.             c = screen_buf[baddr];
  1352.             if (c == CG_space || c == CG_null) {
  1353.                 cursor_move(baddr);
  1354.                 return;
  1355.             } else if (IS_FA(c)) {
  1356.                 baddr = nu_word(baddr);
  1357.                 if (baddr != -1)
  1358.                     cursor_move(baddr);
  1359.                 return;
  1360.             }
  1361.             INC_BA(baddr);
  1362.         } while (baddr != cursor_addr);
  1363.     }
  1364.     /* Otherwise, go to the next unprotected word. */
  1365.     else {
  1366.         baddr = nu_word(cursor_addr);
  1367.         if (baddr != -1)
  1368.             cursor_move(baddr);
  1369.     }
  1370. }
  1371.  
  1372.  
  1373. /*
  1374.  * Cursor up 1 position.
  1375.  */
  1376. void
  1377. Up_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1378. {
  1379.     register int    baddr;
  1380.  
  1381.     action_debug(Up_action, event, params, num_params);
  1382.     if (kybdlock) {
  1383.         enq_ta(Up_action, CN, CN);
  1384.         return;
  1385.     }
  1386. #if defined(X3270_ANSI) /*[*/
  1387.     if (IN_ANSI) {
  1388.         ansi_send_up();
  1389.         return;
  1390.     }
  1391. #endif /*]*/
  1392.     baddr = cursor_addr - COLS;
  1393.     if (baddr < 0)
  1394.         baddr = (cursor_addr + (ROWS * COLS)) - COLS;
  1395.     cursor_move(baddr);
  1396. }
  1397.  
  1398.  
  1399. /*
  1400.  * Cursor down 1 position.
  1401.  */
  1402. void
  1403. Down_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1404. {
  1405.     register int    baddr;
  1406.  
  1407.     action_debug(Down_action, event, params, num_params);
  1408.     if (kybdlock) {
  1409.         enq_ta(Down_action, CN, CN);
  1410.         return;
  1411.     }
  1412. #if defined(X3270_ANSI) /*[*/
  1413.     if (IN_ANSI) {
  1414.         ansi_send_down();
  1415.         return;
  1416.     }
  1417. #endif /*]*/
  1418.     baddr = (cursor_addr + COLS) % (COLS * ROWS);
  1419.     cursor_move(baddr);
  1420. }
  1421.  
  1422.  
  1423. /*
  1424.  * Cursor to first field on next line or any lines after that.
  1425.  */
  1426. void
  1427. Newline_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1428. {
  1429.     register int    baddr;
  1430.     register unsigned char    *fa;
  1431.  
  1432.     action_debug(Newline_action, event, params, num_params);
  1433.     if (kybdlock) {
  1434.         enq_ta(Newline_action, CN, CN);
  1435.         return;
  1436.     }
  1437. #if defined(X3270_ANSI) /*[*/
  1438.     if (IN_ANSI) {
  1439.         net_sendc('\n');
  1440.         return;
  1441.     }
  1442. #endif /*]*/
  1443.     baddr = (cursor_addr + COLS) % (COLS * ROWS);    /* down */
  1444.     baddr = (baddr / COLS) * COLS;            /* 1st col */
  1445.     fa = get_field_attribute(baddr);
  1446.     if (fa != (&screen_buf[baddr]) && !FA_IS_PROTECTED(*fa))
  1447.         cursor_move(baddr);
  1448.     else
  1449.         cursor_move(next_unprotected(baddr));
  1450. }
  1451.  
  1452.  
  1453. /*
  1454.  * DUP key
  1455.  */
  1456. void
  1457. Dup_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1458. {
  1459.     action_debug(Dup_action, event, params, num_params);
  1460.     if (kybdlock) {
  1461.         enq_ta(Dup_action, CN, CN);
  1462.         return;
  1463.     }
  1464. #if defined(X3270_ANSI) /*[*/
  1465.     if (IN_ANSI)
  1466.         return;
  1467. #endif /*]*/
  1468.     if (key_Character(CG_dup, False, False))
  1469.         cursor_move(next_unprotected(cursor_addr));
  1470. }
  1471.  
  1472.  
  1473. /*
  1474.  * FM key
  1475.  */
  1476. void
  1477. FieldMark_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1478. {
  1479.     action_debug(FieldMark_action, event, params, num_params);
  1480.     if (kybdlock) {
  1481.         enq_ta(FieldMark_action, CN, CN);
  1482.         return;
  1483.     }
  1484. #if defined(X3270_ANSI) /*[*/
  1485.     if (IN_ANSI)
  1486.         return;
  1487. #endif /*]*/
  1488.     (void) key_Character(CG_fm, False, False);
  1489. }
  1490.  
  1491.  
  1492. /*
  1493.  * Vanilla AID keys.
  1494.  */
  1495. void
  1496. Enter_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1497. {
  1498.     action_debug(Enter_action, event, params, num_params);
  1499.     if (kybdlock & KL_OIA_MINUS)
  1500.         return;
  1501.     else if (kybdlock)
  1502.         enq_ta(Enter_action, CN, CN);
  1503.     else
  1504.         key_AID(AID_ENTER);
  1505. }
  1506.  
  1507.  
  1508. void
  1509. SysReq_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1510. {
  1511.     action_debug(SysReq_action, event, params, num_params);
  1512.     if (IN_ANSI)
  1513.         return;
  1514. #if defined(X3270_TN3270E) /*[*/
  1515.     if (IN_E) {
  1516.         net_abort();
  1517.     } else
  1518. #endif /*]*/
  1519.     {
  1520.         if (kybdlock & KL_OIA_MINUS)
  1521.             return;
  1522.         else if (kybdlock)
  1523.             enq_ta(SysReq_action, CN, CN);
  1524.         else
  1525.             key_AID(AID_SYSREQ);
  1526.     }
  1527. }
  1528.  
  1529.  
  1530. /*
  1531.  * Clear AID key
  1532.  */
  1533. void
  1534. Clear_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1535. {
  1536.     action_debug(Clear_action, event, params, num_params);
  1537.     if (kybdlock & KL_OIA_MINUS)
  1538.         return;
  1539.     if (kybdlock && CONNECTED) {
  1540.         enq_ta(Clear_action, CN, CN);
  1541.         return;
  1542.     }
  1543. #if defined(X3270_ANSI) /*[*/
  1544.     if (IN_ANSI) {
  1545.         ansi_send_clear();
  1546.         return;
  1547.     }
  1548. #endif /*]*/
  1549.     buffer_addr = 0;
  1550.     ctlr_clear(True);
  1551.     cursor_move(0);
  1552.     if (CONNECTED)
  1553.         key_AID(AID_CLEAR);
  1554. }
  1555.  
  1556.  
  1557. /*
  1558.  * Cursor Select key (light pen simulator).
  1559.  */
  1560. static void
  1561. lightpen_select(int baddr)
  1562. {
  1563.     register unsigned char    *fa, *sel;
  1564.     int designator;
  1565.  
  1566.     fa = get_field_attribute(baddr);
  1567.     if (!FA_IS_SEL(*fa)) {
  1568.         ring_bell();
  1569.         return;
  1570.     }
  1571.     sel = fa + 1;
  1572.     designator = sel - screen_buf;
  1573.     switch (*sel) {
  1574.         case CG_greater:        /* > */
  1575.         ctlr_add(designator, CG_question, 0); /* change to ? */
  1576.         mdt_clear(fa);
  1577.         break;
  1578.         case CG_question:        /* ? */
  1579.         ctlr_add(designator, CG_greater, 0);    /* change to > */
  1580.         mdt_set(fa);
  1581.         break;
  1582.         case CG_space:        /* space */
  1583.         case CG_null:        /* null */
  1584.         mdt_set(fa);
  1585.         key_AID(AID_SELECT);
  1586.         break;
  1587.         case CG_ampersand:        /* & */
  1588.         mdt_set(fa);
  1589.         key_AID(AID_ENTER);
  1590.         break;
  1591.         default:
  1592.         ring_bell();
  1593.         break;
  1594.     }
  1595. }
  1596.  
  1597. /*
  1598.  * Cursor Select key (light pen simulator) -- at the current cursor location.
  1599.  */
  1600. void
  1601. CursorSelect_action(Widget w unused, XEvent *event, String *params,
  1602.     Cardinal *num_params)
  1603. {
  1604.     action_debug(CursorSelect_action, event, params, num_params);
  1605.     if (kybdlock) {
  1606.         enq_ta(CursorSelect_action, CN, CN);
  1607.         return;
  1608.     }
  1609.  
  1610. #if defined(X3270_ANSI) /*[*/
  1611.     if (IN_ANSI)
  1612.         return;
  1613. #endif /*]*/
  1614.     lightpen_select(cursor_addr);
  1615. }
  1616.  
  1617. #if defined(X3270_DISPLAY) /*[*/
  1618. /*
  1619.  * Cursor Select mouse action (light pen simulator).
  1620.  */
  1621. void
  1622. MouseSelect_action(Widget w, XEvent *event, String *params,
  1623.     Cardinal *num_params)
  1624. {
  1625.     action_debug(MouseSelect_action, event, params, num_params);
  1626.     if (w != *screen)
  1627.         return;
  1628.     if (kybdlock)
  1629.         return;
  1630. #if defined(X3270_ANSI) /*[*/
  1631.     if (IN_ANSI)
  1632.         return;
  1633. #endif /*]*/
  1634.     lightpen_select(mouse_baddr(w, event));
  1635. }
  1636. #endif /*]*/
  1637.  
  1638.  
  1639. /*
  1640.  * Erase End Of Field Key.
  1641.  */
  1642. void
  1643. EraseEOF_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1644. {
  1645.     register int    baddr;
  1646.     register unsigned char    *fa;
  1647.  
  1648.     action_debug(EraseEOF_action, event, params, num_params);
  1649.     if (kybdlock) {
  1650.         enq_ta(EraseEOF_action, CN, CN);
  1651.         return;
  1652.     }
  1653. #if defined(X3270_ANSI) /*[*/
  1654.     if (IN_ANSI)
  1655.         return;
  1656. #endif /*]*/
  1657.     baddr = cursor_addr;
  1658.     fa = get_field_attribute(baddr);
  1659.     if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
  1660.         operator_error(KL_OERR_PROTECTED);
  1661.         return;
  1662.     }
  1663.     if (formatted) {    /* erase to next field attribute */
  1664.         do {
  1665.             ctlr_add(baddr, CG_null, 0);
  1666.             INC_BA(baddr);
  1667.         } while (!IS_FA(screen_buf[baddr]));
  1668.         mdt_set(fa);
  1669.     } else {    /* erase to end of screen */
  1670.         do {
  1671.             ctlr_add(baddr, CG_null, 0);
  1672.             INC_BA(baddr);
  1673.         } while (baddr != 0);
  1674.     }
  1675. }
  1676.  
  1677.  
  1678. /*
  1679.  * Erase all Input Key.
  1680.  */
  1681. void
  1682. EraseInput_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1683. {
  1684.     register int    baddr, sbaddr;
  1685.     unsigned char    fa;
  1686.     Boolean        f;
  1687.  
  1688.     action_debug(EraseInput_action, event, params, num_params);
  1689.     if (kybdlock) {
  1690.         enq_ta(EraseInput_action, CN, CN);
  1691.         return;
  1692.     }
  1693. #if defined(X3270_ANSI) /*[*/
  1694.     if (IN_ANSI)
  1695.         return;
  1696. #endif /*]*/
  1697.     if (formatted) {
  1698.         /* find first field attribute */
  1699.         baddr = 0;
  1700.         do {
  1701.             if (IS_FA(screen_buf[baddr]))
  1702.                 break;
  1703.             INC_BA(baddr);
  1704.         } while (baddr != 0);
  1705.         sbaddr = baddr;
  1706.         f = False;
  1707.         do {
  1708.             fa = screen_buf[baddr];
  1709.             if (!FA_IS_PROTECTED(fa)) {
  1710.                 mdt_clear(&screen_buf[baddr]);
  1711.                 do {
  1712.                     INC_BA(baddr);
  1713.                     if (!f) {
  1714.                         cursor_move(baddr);
  1715.                         f = True;
  1716.                     }
  1717.                     if (!IS_FA(screen_buf[baddr])) {
  1718.                         ctlr_add(baddr, CG_null, 0);
  1719.                     }
  1720.                 }        while (!IS_FA(screen_buf[baddr]));
  1721.             } else {    /* skip protected */
  1722.                 do {
  1723.                     INC_BA(baddr);
  1724.                 } while (!IS_FA(screen_buf[baddr]));
  1725.             }
  1726.         } while (baddr != sbaddr);
  1727.         if (!f)
  1728.             cursor_move(0);
  1729.     } else {
  1730.         ctlr_clear(True);
  1731.         cursor_move(0);
  1732.     }
  1733. }
  1734.  
  1735.  
  1736.  
  1737. /*
  1738.  * Delete word key.  Backspaces the cursor until it hits the front of a word,
  1739.  * deletes characters until it hits a blank or null, and deletes all of these
  1740.  * but the last.
  1741.  *
  1742.  * Which is to say, does a ^W.
  1743.  */
  1744. void
  1745. DeleteWord_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1746. {
  1747.     register int    baddr, baddr2, front_baddr, back_baddr, end_baddr;
  1748.     register unsigned char    *fa;
  1749.  
  1750.     action_debug(DeleteWord_action, event, params, num_params);
  1751.     if (kybdlock) {
  1752.         enq_ta(DeleteWord_action, CN, CN);
  1753.         return;
  1754.     }
  1755. #if defined(X3270_ANSI) /*[*/
  1756.     if (IN_ANSI) {
  1757.         net_send_werase();
  1758.         return;
  1759.     }
  1760. #endif /*]*/
  1761.     if (!formatted)
  1762.         return;
  1763.  
  1764.     baddr = cursor_addr;
  1765.     fa = get_field_attribute(baddr);
  1766.  
  1767.     /* Make sure we're on a modifiable field. */
  1768.     if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
  1769.         operator_error(KL_OERR_PROTECTED);
  1770.         return;
  1771.     }
  1772.  
  1773.     /* Search backwards for a non-blank character. */
  1774.     front_baddr = baddr;
  1775.     while (screen_buf[front_baddr] == CG_space ||
  1776.            screen_buf[front_baddr] == CG_null)
  1777.         DEC_BA(front_baddr);
  1778.  
  1779.     /* If we ran into the edge of the field without seeing any non-blanks,
  1780.        there isn't any word to delete; just move the cursor. */
  1781.     if (IS_FA(screen_buf[front_baddr])) {
  1782.         cursor_move(front_baddr+1);
  1783.         return;
  1784.     }
  1785.  
  1786.     /* front_baddr is now pointing at a non-blank character.  Now search
  1787.        for the first blank to the left of that (or the edge of the field),
  1788.        leaving front_baddr pointing at the the beginning of the word. */
  1789.     while (!IS_FA(screen_buf[front_baddr]) &&
  1790.            screen_buf[front_baddr] != CG_space &&
  1791.            screen_buf[front_baddr] != CG_null)
  1792.         DEC_BA(front_baddr);
  1793.     INC_BA(front_baddr);
  1794.  
  1795.     /* Find the end of the word, searching forward for the edge of the
  1796.        field or a non-blank. */
  1797.     back_baddr = front_baddr;
  1798.     while (!IS_FA(screen_buf[back_baddr]) &&
  1799.            screen_buf[back_baddr] != CG_space &&
  1800.            screen_buf[back_baddr] != CG_null)
  1801.         INC_BA(back_baddr);
  1802.  
  1803.     /* Find the start of the next word, leaving back_baddr pointing at it
  1804.        or at the end of the field. */
  1805.     while (screen_buf[back_baddr] == CG_space ||
  1806.            screen_buf[back_baddr] == CG_null)
  1807.         INC_BA(back_baddr);
  1808.  
  1809.     /* Find the end of the field, leaving end_baddr pointing at the field
  1810.        attribute of the start of the next field. */
  1811.     end_baddr = back_baddr;
  1812.     while (!IS_FA(screen_buf[end_baddr]))
  1813.         INC_BA(end_baddr);
  1814.  
  1815.     /* Copy any text to the right of the word we are deleting. */
  1816.     baddr = front_baddr;
  1817.     baddr2 = back_baddr;
  1818.     while (baddr2 != end_baddr) {
  1819.         ctlr_add(baddr, screen_buf[baddr2], 0);
  1820.         INC_BA(baddr);
  1821.         INC_BA(baddr2);
  1822.     }
  1823.  
  1824.     /* Insert nulls to pad out the end of the field. */
  1825.     while (baddr != end_baddr) {
  1826.         ctlr_add(baddr, CG_null, 0);
  1827.         INC_BA(baddr);
  1828.     }
  1829.  
  1830.     /* Set the MDT and move the cursor. */
  1831.     mdt_set(fa);
  1832.     cursor_move(front_baddr);
  1833. }
  1834.  
  1835.  
  1836.  
  1837. /*
  1838.  * Delete field key.  Similar to EraseEOF, but it wipes out the entire field
  1839.  * rather than just to the right of the cursor, and it leaves the cursor at
  1840.  * the front of the field.
  1841.  *
  1842.  * Which is to say, does a ^U.
  1843.  */
  1844. void
  1845. DeleteField_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1846. {
  1847.     register int    baddr;
  1848.     register unsigned char    *fa;
  1849.  
  1850.     action_debug(DeleteField_action, event, params, num_params);
  1851.     if (kybdlock) {
  1852.         enq_ta(DeleteField_action, CN, CN);
  1853.         return;
  1854.     }
  1855. #if defined(X3270_ANSI) /*[*/
  1856.     if (IN_ANSI) {
  1857.         net_send_kill();
  1858.         return;
  1859.     }
  1860. #endif /*]*/
  1861.     if (!formatted)
  1862.         return;
  1863.  
  1864.     baddr = cursor_addr;
  1865.     fa = get_field_attribute(baddr);
  1866.     if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
  1867.         operator_error(KL_OERR_PROTECTED);
  1868.         return;
  1869.     }
  1870.     while (!IS_FA(screen_buf[baddr]))
  1871.         DEC_BA(baddr);
  1872.     INC_BA(baddr);
  1873.     cursor_move(baddr);
  1874.     while (!IS_FA(screen_buf[baddr])) {
  1875.         ctlr_add(baddr, CG_null, 0);
  1876.         INC_BA(baddr);
  1877.     }
  1878.     mdt_set(fa);
  1879. }
  1880.  
  1881.  
  1882.  
  1883. /*
  1884.  * Set insert mode key.
  1885.  */
  1886. void
  1887. Insert_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1888. {
  1889.     action_debug(Insert_action, event, params, num_params);
  1890.     if (kybdlock) {
  1891.         enq_ta(Insert_action, CN, CN);
  1892.         return;
  1893.     }
  1894. #if defined(X3270_ANSI) /*[*/
  1895.     if (IN_ANSI)
  1896.         return;
  1897. #endif /*]*/
  1898.     insert_mode(True);
  1899. }
  1900.  
  1901.  
  1902. /*
  1903.  * Toggle insert mode key.
  1904.  */
  1905. void
  1906. ToggleInsert_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1907. {
  1908.     action_debug(ToggleInsert_action, event, params, num_params);
  1909.     if (kybdlock) {
  1910.         enq_ta(ToggleInsert_action, CN, CN);
  1911.         return;
  1912.     }
  1913. #if defined(X3270_ANSI) /*[*/
  1914.     if (IN_ANSI)
  1915.         return;
  1916. #endif /*]*/
  1917.     if (insert)
  1918.         insert_mode(False);
  1919.     else
  1920.         insert_mode(True);
  1921. }
  1922.  
  1923.  
  1924. /*
  1925.  * Toggle reverse mode key.
  1926.  */
  1927. void
  1928. ToggleReverse_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1929. {
  1930.     action_debug(ToggleReverse_action, event, params, num_params);
  1931.     if (kybdlock) {
  1932.         enq_ta(ToggleReverse_action, CN, CN);
  1933.         return;
  1934.     }
  1935. #if defined(X3270_ANSI) /*[*/
  1936.     if (IN_ANSI)
  1937.         return;
  1938. #endif /*]*/
  1939.     reverse_mode(!reverse);
  1940. }
  1941.  
  1942.  
  1943. /*
  1944.  * Move the cursor to the first blank after the last nonblank in the
  1945.  * field, or if the field is full, to the last character in the field.
  1946.  */
  1947. void
  1948. FieldEnd_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  1949. {
  1950.     int    baddr;
  1951.     unsigned char    *fa, c;
  1952.     int    last_nonblank = -1;
  1953.  
  1954.     action_debug(FieldEnd_action, event, params, num_params);
  1955.     if (kybdlock) {
  1956.         enq_ta(FieldEnd_action, CN, CN);
  1957.         return;
  1958.     }
  1959. #if defined(X3270_ANSI) /*[*/
  1960.     if (IN_ANSI)
  1961.         return;
  1962. #endif /*]*/
  1963.     if (!formatted)
  1964.         return;
  1965.     baddr = cursor_addr;
  1966.     fa = get_field_attribute(baddr);
  1967.     if (fa == &screen_buf[baddr] || FA_IS_PROTECTED(*fa))
  1968.         return;
  1969.  
  1970.     baddr = fa - screen_buf;
  1971.     while (True) {
  1972.         INC_BA(baddr);
  1973.         c = screen_buf[baddr];
  1974.         if (IS_FA(c))
  1975.             break;
  1976.         if (c != CG_null && c != CG_space)
  1977.             last_nonblank = baddr;
  1978.     }
  1979.  
  1980.     if (last_nonblank == -1) {
  1981.         baddr = fa - screen_buf;
  1982.         INC_BA(baddr);
  1983.     } else {
  1984.         baddr = last_nonblank;
  1985.         INC_BA(baddr);
  1986.         if (IS_FA(screen_buf[baddr]))
  1987.             baddr = last_nonblank;
  1988.     }
  1989.     cursor_move(baddr);
  1990. }
  1991.  
  1992. /*
  1993.  * MoveCursor action.  Depending on arguments, this is either a move to the
  1994.  * mouse cursor position, or to an absolute location.
  1995.  */
  1996. void
  1997. MoveCursor_action(Widget w, XEvent *event, String *params, Cardinal *num_params)
  1998. {
  1999.     register int baddr;
  2000.     int row, col;
  2001.  
  2002.     action_debug(MoveCursor_action, event, params, num_params);
  2003.  
  2004.     if (kybdlock) {
  2005.         if (*num_params == 2)
  2006.             enq_ta(MoveCursor_action, params[0], params[1]);
  2007.         return;
  2008.     }
  2009.  
  2010.     switch (*num_params) {
  2011. #if defined(X3270_DISPLAY) /*[*/
  2012.         case 0:        /* mouse click, presumably */
  2013.         if (w != *screen)
  2014.             return;
  2015.         cursor_move(mouse_baddr(w, event));
  2016.         break;
  2017. #endif /*]*/
  2018.         case 2:        /* probably a macro call */
  2019.         row = atoi(params[0]);
  2020.         col = atoi(params[1]);
  2021.         if (!IN_3270) {
  2022.             row--;
  2023.             col--;
  2024.         }
  2025.         if (row < 0)
  2026.             row = 0;
  2027.         if (col < 0)
  2028.             col = 0;
  2029.         baddr = ((row * COLS) + col) % (ROWS * COLS);
  2030.         cursor_move(baddr);
  2031.         break;
  2032.         default:        /* couln't say */
  2033.         popup_an_error("%s requires 0 or 2 arguments",
  2034.             action_name(MoveCursor_action));
  2035.         break;
  2036.     }
  2037. }
  2038.  
  2039.  
  2040.  
  2041.  
  2042. /*
  2043.  * Key action.
  2044.  */
  2045. void
  2046. Key_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2047. {
  2048.     Cardinal i;
  2049.     KeySym k;
  2050.     enum keytype keytype;
  2051.  
  2052.     action_debug(Key_action, event, params, num_params);
  2053.     for (i = 0; i < *num_params; i++) {
  2054.         char *s = params[i];
  2055.  
  2056.         k = MyStringToKeysym(s, &keytype);
  2057.         if (k == NoSymbol) {
  2058.             popup_an_error("%s: Nonexistent or invalid KeySym: %s",
  2059.                 action_name(Key_action), s);
  2060.             continue;
  2061.         }
  2062.         if (k & ~0xff) {
  2063.             popup_an_error("%s: Invalid KeySym: %s",
  2064.                 action_name(Key_action), s);
  2065.             continue;
  2066.         }
  2067.         key_ACharacter((unsigned char)(k & 0xff), keytype, IA_KEY);
  2068.     }
  2069. }
  2070.  
  2071. /*
  2072.  * String action.
  2073.  */
  2074. void
  2075. String_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2076. {
  2077.     Cardinal i;
  2078.     int len = 0;
  2079.     char *s;
  2080.  
  2081.     action_debug(String_action, event, params, num_params);
  2082.  
  2083.     /* Determine the total length of the strings. */
  2084.     for (i = 0; i < *num_params; i++)
  2085.         len += strlen(params[i]);
  2086.     if (!len)
  2087.         return;
  2088.  
  2089.     /* Allocate a block of memory and copy them in. */
  2090.     s = Malloc(len + 1);
  2091.     *s = '\0';
  2092.     for (i = 0; i < *num_params; i++)
  2093.         (void) strcat(s, params[i]);
  2094.  
  2095.     /* Set a pending string. */
  2096.     ps_set(s, False);
  2097. }
  2098.  
  2099. /*
  2100.  * HexString action.
  2101.  */
  2102. void
  2103. HexString_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2104. {
  2105.     Cardinal i;
  2106.     int len = 0;
  2107.     char *s;
  2108.     char *t;
  2109.  
  2110.     action_debug(HexString_action, event, params, num_params);
  2111.  
  2112.     /* Determine the total length of the strings. */
  2113.     for (i = 0; i < *num_params; i++) {
  2114.         t = params[i];
  2115.         if (!strncmp(t, "0x", 2) || !strncmp(t, "0X", 2))
  2116.             t += 2;
  2117.         len += strlen(t);
  2118.     }
  2119.     if (!len)
  2120.         return;
  2121.  
  2122.     /* Allocate a block of memory and copy them in. */
  2123.     s = Malloc(len + 1);
  2124.     *s = '\0';
  2125.     for (i = 0; i < *num_params; i++) {
  2126.         t = params[i];
  2127.         if (!strncmp(t, "0x", 2) || !strncmp(t, "0X", 2))
  2128.             t += 2;
  2129.         (void) strcat(s, t);
  2130.     }
  2131.  
  2132.     /* Set a pending string. */
  2133.     ps_set(s, True);
  2134. }
  2135.  
  2136. /*
  2137.  * Dual-mode action for the "asciicircum" ("^") key:
  2138.  *  If in ANSI mode, pass through untranslated.
  2139.  *  If in 3270 mode, translate to "notsign".
  2140.  */
  2141. void
  2142. CircumNot_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2143. {
  2144.     action_debug(CircumNot_action, event, params, num_params);
  2145.  
  2146.     if (IN_3270 && composing == NONE)
  2147.         key_ACharacter(0xac, KT_STD, IA_KEY);
  2148.     else
  2149.         key_ACharacter('^', KT_STD, IA_KEY);
  2150. }
  2151.  
  2152. /* PA key action for String actions */
  2153. static void
  2154. do_pa(unsigned n)
  2155. {
  2156.     if (n < 1 || n > PA_SZ) {
  2157.         popup_an_error("Unknown PA key %d", n);
  2158.         return;
  2159.     }
  2160.     if (kybdlock) {
  2161.         char nn[3];
  2162.  
  2163.         (void) sprintf(nn, "%d", n);
  2164.         enq_ta(PA_action, nn, CN);
  2165.         return;
  2166.     }
  2167.     key_AID(pa_xlate[n-1]);
  2168. }
  2169.  
  2170. /* PF key action for String actions */
  2171. static void
  2172. do_pf(unsigned n)
  2173. {
  2174.     if (n < 1 || n > PF_SZ) {
  2175.         popup_an_error("Unknown PF key %d", n);
  2176.         return;
  2177.     }
  2178.     if (kybdlock) {
  2179.         char nn[3];
  2180.  
  2181.         (void) sprintf(nn, "%d", n);
  2182.         enq_ta(PF_action, nn, CN);
  2183.         return;
  2184.     }
  2185.     key_AID(pf_xlate[n-1]);
  2186. }
  2187.  
  2188. /*
  2189.  * Set or clear the keyboard scroll lock.
  2190.  */
  2191. void
  2192. kybd_scroll_lock(Boolean lock)
  2193. {
  2194.     if (!IN_3270)
  2195.         return;
  2196.     if (lock)
  2197.         kybdlock_set(KL_SCROLLED, "kybd_scroll_lock");
  2198.     else
  2199.         kybdlock_clr(KL_SCROLLED, "kybd_scroll_lock");
  2200. }
  2201.  
  2202. /*
  2203.  * Move the cursor back within the legal paste area.
  2204.  * Returns a Boolean indicating success.
  2205.  */
  2206. static Boolean
  2207. remargin(int lmargin)
  2208. {
  2209.     Boolean ever = False;
  2210.     int baddr, b0 = 0;
  2211.     unsigned char *fa;
  2212.  
  2213.     baddr = cursor_addr;
  2214.     while (BA_TO_COL(baddr) < lmargin) {
  2215.         baddr = ROWCOL_TO_BA(BA_TO_ROW(baddr), lmargin);
  2216.         if (!ever) {
  2217.             b0 = baddr;
  2218.             ever = True;
  2219.         }
  2220.         fa = get_field_attribute(baddr);
  2221.         if (fa == &screen_buf[baddr] || FA_IS_PROTECTED(*fa)) {
  2222.             baddr = next_unprotected(baddr);
  2223.             if (baddr <= b0)
  2224.                 return False;
  2225.         }
  2226.     }
  2227.  
  2228.     cursor_move(baddr);
  2229.     return True;
  2230. }
  2231.  
  2232. /*
  2233.  * Pretend that a sequence of keys was entered at the keyboard.
  2234.  *
  2235.  * "Pasting" means that the sequence came from the X clipboard.  Returns are
  2236.  * ignored; newlines mean "move to beginning of next line"; tabs and formfeeds
  2237.  * become spaces.  Backslashes are not special, but ASCII ESC characters are
  2238.  * used to signify 3270 Graphic Escapes.
  2239.  *
  2240.  * "Not pasting" means that the sequence is a login string specified in the
  2241.  * hosts file, or a parameter to the String action.  Returns are "move to
  2242.  * beginning of next line"; newlines mean "Enter AID" and the termination of
  2243.  * processing the string.  Backslashes are processed as in C.
  2244.  *
  2245.  * Returns the number of unprocessed characters.
  2246.  */
  2247. int
  2248. emulate_input(char *s, int len, Boolean pasting)
  2249. {
  2250.     char c;
  2251.     enum { BASE, BACKSLASH, BACKX, BACKP, BACKPA, BACKPF, OCTAL, HEX,
  2252.            XGE } state = BASE;
  2253.     int literal = 0;
  2254.     int nc = 0;
  2255.     enum iaction ia = pasting ? IA_PASTE : IA_STRING;
  2256.     int orig_addr = cursor_addr;
  2257.     int orig_col = BA_TO_COL(cursor_addr);
  2258.  
  2259.     /*
  2260.      * In the switch statements below, "break" generally means "consume
  2261.      * this character," while "continue" means "rescan this character."
  2262.      */
  2263.     while (len) {
  2264.  
  2265.         /*
  2266.          * It isn't possible to unlock the keyboard from a string,
  2267.          * so if the keyboard is locked, it's fatal
  2268.          */
  2269.         if (kybdlock) {
  2270.             trace_event("  keyboard locked, string dropped\n");
  2271.             return 0;
  2272.         }
  2273.  
  2274.         if (pasting && IN_3270) {
  2275.  
  2276.             /* Check for cursor wrap to top of screen. */
  2277.             if (cursor_addr < orig_addr)
  2278.                 return len-1;        /* wrapped */
  2279.  
  2280.             /* Jump cursor over left margin. */
  2281.             if (toggled(MARGINED_PASTE) &&
  2282.                 BA_TO_COL(cursor_addr) < orig_col) {
  2283.                 if (!remargin(orig_col))
  2284.                     return len-1;
  2285.             }
  2286.         }
  2287.  
  2288.         c = *s;
  2289.         switch (state) {
  2290.             case BASE:
  2291.             switch (c) {
  2292.                 case '\b':
  2293.                 action_internal(Left_action, ia, CN, CN);
  2294.                 continue;
  2295.                 case '\f':
  2296.                 if (pasting) {
  2297.                     key_ACharacter((unsigned char) ' ',
  2298.                         KT_STD, ia);
  2299.                 } else {
  2300.                     action_internal(Clear_action, ia, CN, CN);
  2301.                     if (IN_3270)
  2302.                         return len-1;
  2303.                     else
  2304.                         break;
  2305.                 }
  2306.                 case '\n':
  2307.                 if (pasting)
  2308.                     action_internal(Newline_action, ia, CN, CN);
  2309.                 else {
  2310.                     action_internal(Enter_action, ia, CN, CN);
  2311.                     if (IN_3270)
  2312.                         return len-1;
  2313.                 }
  2314.                 break;
  2315.                 case '\r':    /* ignored */
  2316.                 break;
  2317.                 case '\t':
  2318.                 action_internal(Tab_action, ia, CN, CN);
  2319.                 break;
  2320.                 case '\\':    /* backslashes are NOT special when pasting */
  2321.                 if (!pasting)
  2322.                     state = BACKSLASH;
  2323.                 else
  2324.                     key_ACharacter((unsigned char) c,
  2325.                         KT_STD, ia);
  2326.                 break;
  2327.                 case '\033': /* ESC is special only when pasting */
  2328.                 if (pasting)
  2329.                     state = XGE;
  2330.                 break;
  2331.                 case '[':    /* APL left bracket */
  2332.                 if (pasting && appres.apl_mode)
  2333.                     key_ACharacter(
  2334.                         (unsigned char) XK_Yacute,
  2335.                         KT_GE, ia);
  2336.                 else
  2337.                     key_ACharacter((unsigned char) c,
  2338.                         KT_STD, ia);
  2339.                 break;
  2340.                 case ']':    /* APL right bracket */
  2341.                 if (pasting && appres.apl_mode)
  2342.                     key_ACharacter(
  2343.                         (unsigned char) XK_diaeresis,
  2344.                         KT_GE, ia);
  2345.                 else
  2346.                     key_ACharacter((unsigned char) c,
  2347.                         KT_STD, ia);
  2348.                 break;
  2349.             default:
  2350.                 key_ACharacter((unsigned char) c, KT_STD,
  2351.                     ia);
  2352.                 break;
  2353.             }
  2354.             break;
  2355.             case BACKSLASH:    /* last character was a backslash */
  2356.             switch (c) {
  2357.                 case 'a':
  2358.                 popup_an_error("%s: Bell not supported",
  2359.                     action_name(String_action));
  2360.                 state = BASE;
  2361.                 break;
  2362.                 case 'b':
  2363.                 action_internal(Left_action, ia, CN, CN);
  2364.                 state = BASE;
  2365.                 break;
  2366.                 case 'f':
  2367.                 action_internal(Clear_action, ia, CN, CN);
  2368.                 state = BASE;
  2369.                 if (IN_3270)
  2370.                     return len-1;
  2371.                 else
  2372.                     break;
  2373.                 case 'n':
  2374.                 action_internal(Enter_action, ia, CN, CN);
  2375.                 state = BASE;
  2376.                 if (IN_3270)
  2377.                     return len-1;
  2378.                 else
  2379.                     break;
  2380.                 case 'p':
  2381.                 state = BACKP;
  2382.                 break;
  2383.                 case 'r':
  2384.                 action_internal(Newline_action, ia, CN, CN);
  2385.                 state = BASE;
  2386.                 break;
  2387.                 case 't':
  2388.                 action_internal(Tab_action, ia, CN, CN);
  2389.                 state = BASE;
  2390.                 break;
  2391.                 case 'v':
  2392.                 popup_an_error("%s: Vertical tab not supported",
  2393.                     action_name(String_action));
  2394.                 state = BASE;
  2395.                 break;
  2396.                 case 'x':
  2397.                 state = BACKX;
  2398.                 break;
  2399.                 case '\\':
  2400.                 key_ACharacter((unsigned char) c, KT_STD, ia);
  2401.                 state = BASE;
  2402.                 break;
  2403.                 case '0': 
  2404.                 case '1': 
  2405.                 case '2': 
  2406.                 case '3':
  2407.                 case '4': 
  2408.                 case '5': 
  2409.                 case '6': 
  2410.                 case '7':
  2411.                 state = OCTAL;
  2412.                 literal = 0;
  2413.                 nc = 0;
  2414.                 continue;
  2415.             default:
  2416.                 state = BASE;
  2417.                 continue;
  2418.             }
  2419.             break;
  2420.             case BACKP:    /* last two characters were "\p" */
  2421.             switch (c) {
  2422.                 case 'a':
  2423.                 literal = 0;
  2424.                 nc = 0;
  2425.                 state = BACKPA;
  2426.                 break;
  2427.                 case 'f':
  2428.                 literal = 0;
  2429.                 nc = 0;
  2430.                 state = BACKPF;
  2431.                 break;
  2432.                 default:
  2433.                 popup_an_error("%s: Unknown character after \\p",
  2434.                     action_name(String_action));
  2435.                 state = BASE;
  2436.                 break;
  2437.             }
  2438.             break;
  2439.             case BACKPF: /* last three characters were "\pf" */
  2440.             if (nc < 2 && isdigit(c)) {
  2441.                 literal = (literal * 10) + (c - '0');
  2442.                 nc++;
  2443.             } else if (!nc) {
  2444.                 popup_an_error("%s: Unknown character after \\pf",
  2445.                     action_name(String_action));
  2446.                 state = BASE;
  2447.             } else {
  2448.                 do_pf(literal);
  2449.                 if (IN_3270)
  2450.                     return len-1;
  2451.                 state = BASE;
  2452.                 continue;
  2453.             }
  2454.             break;
  2455.             case BACKPA: /* last three characters were "\pa" */
  2456.             if (nc < 1 && isdigit(c)) {
  2457.                 literal = (literal * 10) + (c - '0');
  2458.                 nc++;
  2459.             } else if (!nc) {
  2460.                 popup_an_error("%s: Unknown character after \\pa",
  2461.                     action_name(String_action));
  2462.                 state = BASE;
  2463.             } else {
  2464.                 do_pa(literal);
  2465.                 if (IN_3270)
  2466.                     return len-1;
  2467.                 state = BASE;
  2468.                 continue;
  2469.             }
  2470.             break;
  2471.             case BACKX:    /* last two characters were "\x" */
  2472.             if (isxdigit(c)) {
  2473.                 state = HEX;
  2474.                 literal = 0;
  2475.                 nc = 0;
  2476.                 continue;
  2477.             } else {
  2478.                 popup_an_error("%s: Missing hex digits after \\x",
  2479.                     action_name(String_action));
  2480.                 state = BASE;
  2481.                 continue;
  2482.             }
  2483.             case OCTAL:    /* have seen \ and one or more octal digits */
  2484.             if (nc < 3 && isdigit(c) && c < '8') {
  2485.                 literal = (literal * 8) + FROM_HEX(c);
  2486.                 nc++;
  2487.                 break;
  2488.             } else {
  2489.                 key_ACharacter((unsigned char) literal, KT_STD,
  2490.                     ia);
  2491.                 state = BASE;
  2492.                 continue;
  2493.             }
  2494.             case HEX:    /* have seen \ and one or more hex digits */
  2495.             if (nc < 2 && isxdigit(c)) {
  2496.                 literal = (literal * 16) + FROM_HEX(c);
  2497.                 nc++;
  2498.                 break;
  2499.             } else {
  2500.                 key_ACharacter((unsigned char) literal, KT_STD,
  2501.                     ia);
  2502.                 state = BASE;
  2503.                 continue;
  2504.             }
  2505.             case XGE:    /* have seen ESC */
  2506.             switch (c) {
  2507.                 case ';':    /* FM */
  2508.                 key_Character(CG_fm, False, True);
  2509.                 break;
  2510.                 case '*':    /* DUP */
  2511.                 key_Character(CG_dup, False, True);
  2512.                 break;
  2513.                 default:
  2514.                 key_ACharacter((unsigned char) c, KT_GE, ia);
  2515.                 break;
  2516.             }
  2517.             state = BASE;
  2518.             break;
  2519.         }
  2520.         s++;
  2521.         len--;
  2522.     }
  2523.  
  2524.     switch (state) {
  2525.         case OCTAL:
  2526.         case HEX:
  2527.         key_ACharacter((unsigned char) literal, KT_STD, ia);
  2528.         state = BASE;
  2529.         break;
  2530.         case BACKPF:
  2531.         if (nc > 0) {
  2532.             do_pf(literal);
  2533.             state = BASE;
  2534.         }
  2535.         break;
  2536.         case BACKPA:
  2537.         if (nc > 0) {
  2538.             do_pa(literal);
  2539.             state = BASE;
  2540.         }
  2541.         break;
  2542.         default:
  2543.         break;
  2544.     }
  2545.  
  2546.     if (state != BASE)
  2547.         popup_an_error("%s: Missing data after \\",
  2548.             action_name(String_action));
  2549.  
  2550.     return len;
  2551. }
  2552.  
  2553. /*
  2554.  * Pretend that a sequence of hexadecimal characters was entered at the
  2555.  * keyboard.  The input is a sequence of hexadecimal bytes, 2 characters
  2556.  * per byte.  If connected in ANSI mode, these are treated as ASCII
  2557.  * characters; if in 3270 mode, they are considered EBCDIC.
  2558.  *
  2559.  * Graphic Escapes are handled as \E.
  2560.  */
  2561. void
  2562. hex_input(char *s)
  2563. {
  2564.     char *t;
  2565.     Boolean escaped;
  2566. #if defined(X3270_ANSI) /*[*/
  2567.     unsigned char *xbuf = (unsigned char *)NULL;
  2568.     unsigned char *tbuf = (unsigned char *)NULL;
  2569.     int nbytes = 0;
  2570. #endif /*]*/
  2571.  
  2572.     /* Validate the string. */
  2573.     if (strlen(s) % 2) {
  2574.         popup_an_error("%s: Odd number of characters in specification",
  2575.             action_name(HexString_action));
  2576.         return;
  2577.     }
  2578.     t = s;
  2579.     escaped = False;
  2580.     while (*t) {
  2581.         if (isxdigit(*t) && isxdigit(*(t + 1))) {
  2582.             escaped = False;
  2583. #if defined(X3270_ANSI) /*[*/
  2584.             nbytes++;
  2585. #endif /*]*/
  2586.         } else if (!strncmp(t, "\\E", 2) || !strncmp(t, "\\e", 2)) {
  2587.             if (escaped) {
  2588.                 popup_an_error("%s: Double \\E",
  2589.                     action_name(HexString_action));
  2590.                 return;
  2591.             }
  2592.             if (!IN_3270) {
  2593.                 popup_an_error("%s: \\E in ANSI mode",
  2594.                     action_name(HexString_action));
  2595.                 return;
  2596.             }
  2597.             escaped = True;
  2598.         } else {
  2599.             popup_an_error("%s: Illegal character in specification",
  2600.                 action_name(HexString_action));
  2601.             return;
  2602.         }
  2603.         t += 2;
  2604.     }
  2605.     if (escaped) {
  2606.         popup_an_error("%s: Nothing follows \\E",
  2607.             action_name(HexString_action));
  2608.         return;
  2609.     }
  2610.  
  2611. #if defined(X3270_ANSI) /*[*/
  2612.     /* Allocate a temporary buffer. */
  2613.     if (!IN_3270 && nbytes)
  2614.         tbuf = xbuf = (unsigned char *)Malloc(nbytes);
  2615. #endif /*]*/
  2616.  
  2617.     /* Pump it in. */
  2618.     t = s;
  2619.     escaped = False;
  2620.     while (*t) {
  2621.         if (isxdigit(*t) && isxdigit(*(t + 1))) {
  2622.             unsigned c;
  2623.  
  2624.             c = (FROM_HEX(*t) * 16) + FROM_HEX(*(t + 1));
  2625.             if (IN_3270)
  2626.                 key_Character(ebc2cg[c], escaped, True);
  2627. #if defined(X3270_ANSI) /*[*/
  2628.             else
  2629.                 *tbuf++ = (unsigned char)c;
  2630. #endif /*]*/
  2631.             escaped = False;
  2632.         } else if (!strncmp(t, "\\E", 2) || !strncmp(t, "\\e", 2)) {
  2633.             escaped = True;
  2634.         }
  2635.         t += 2;
  2636.     }
  2637. #if defined(X3270_ANSI) /*[*/
  2638.     if (!IN_3270 && nbytes) {
  2639.         net_hexansi_out(xbuf, nbytes);
  2640.         Free(xbuf);
  2641.     }
  2642. #endif /*]*/
  2643. }
  2644.  
  2645. void
  2646. ignore_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2647. {
  2648.     action_debug(ignore_action, event, params, num_params);
  2649. }
  2650.  
  2651. #if defined(X3270_FT) /*[*/
  2652. /*
  2653.  * Set up the cursor and input field for command input.
  2654.  * Returns the length of the input field, or 0 if there is no field
  2655.  * to set up.
  2656.  */
  2657. int
  2658. kybd_prime(void)
  2659. {
  2660.     int baddr;
  2661.     register unsigned char *fa;
  2662.     int len = 0;
  2663.  
  2664.     /*
  2665.      * No point in trying if the screen isn't formatted, the keyboard
  2666.      * is locked, or we aren't in 3270 mode.
  2667.      */
  2668.     if (!formatted || kybdlock || !IN_3270)
  2669.         return 0;
  2670.  
  2671.     fa = get_field_attribute(cursor_addr);
  2672.     if (IS_FA(screen_buf[cursor_addr]) || FA_IS_PROTECTED(*fa)) {
  2673.         /*
  2674.          * The cursor is not in an unprotected field.  Find the
  2675.          * next one.
  2676.          */
  2677.         baddr = next_unprotected(cursor_addr);
  2678.  
  2679.         /* If there isn't any, give up. */
  2680.         if (!baddr)
  2681.             return 0;
  2682.  
  2683.         /* Move the cursor there. */
  2684.     } else {
  2685.         /* Already in an unprotected field.  Find its start. */
  2686.         baddr = cursor_addr;
  2687.         while (!IS_FA(screen_buf[baddr])) {
  2688.             DEC_BA(baddr);
  2689.         }
  2690.         INC_BA(baddr);
  2691.     }
  2692.  
  2693.     /* Move the cursor to the beginning of the field. */
  2694.     cursor_move(baddr);
  2695.  
  2696.     /* Erase it. */
  2697.     while (!IS_FA(screen_buf[baddr])) {
  2698.         ctlr_add(baddr, 0, 0);
  2699.         len++;
  2700.         INC_BA(baddr);
  2701.     }
  2702.  
  2703.     /* Return the field length. */
  2704.     return len;
  2705. }
  2706. #endif /*]*/
  2707.  
  2708. /*
  2709.  * Translate a keysym name to a keysym, including APL and extended
  2710.  * characters.
  2711.  */
  2712. static KeySym
  2713. MyStringToKeysym(char *s, enum keytype *keytypep)
  2714. {
  2715.     KeySym k;
  2716.     int cc;
  2717.     char *ptr;
  2718.  
  2719. #if defined(X3270_APL) /*[*/
  2720.     if (!strncmp(s, "apl_", 4)) {
  2721.         int is_ge;
  2722.  
  2723.         k = APLStringToKeysym(s, &is_ge);
  2724.         if (is_ge)
  2725.             *keytypep = KT_GE;
  2726.         else
  2727.             *keytypep = KT_STD;
  2728.     } else
  2729. #endif /*]*/
  2730.     {
  2731.         k = StringToKeysym(s);
  2732.         *keytypep = KT_STD;
  2733.     }
  2734.     if (k == NoSymbol && strlen(s) == 1)
  2735.         k = s[0] & 0xff;
  2736.     if (k < ' ')
  2737.         k = NoSymbol;
  2738.     else if (k > 0xff) {
  2739.         int i;
  2740.  
  2741.         for (i = 0; i < nxk; i++)
  2742.             if (xk[i].key == k) {
  2743.                 k = xk[i].assoc;
  2744.                 break;
  2745.             }
  2746.         if (k > 0xff)
  2747.             k = NoSymbol;
  2748.     }
  2749.  
  2750.     /* Allow arbitrary values, e.g., 0x03 for ^C. */
  2751.     if (k == NoSymbol &&
  2752.         (cc = strtoul(s, &ptr, 0)) > 0 &&
  2753.         cc < 0xff &&
  2754.         ptr != s &&
  2755.         *ptr == '\0')
  2756.         k = cc;
  2757.  
  2758.     return k;
  2759. }
  2760.  
  2761. /* Add a key to the extended association table. */
  2762. void
  2763. add_xk(KeySym key, KeySym assoc)
  2764. {
  2765.     int i;
  2766.  
  2767.     for (i = 0; i < nxk; i++)
  2768.         if (xk[i].key == key) {
  2769.             xk[i].assoc = assoc;
  2770.             return;
  2771.         }
  2772.     xk = (struct xks *)Realloc(xk, (nxk + 1) * sizeof(struct xks));
  2773.     xk[nxk].key = key;
  2774.     xk[nxk].assoc = assoc;
  2775.     nxk++;
  2776. }
  2777.  
  2778. /* Clear the extended association table. */
  2779. void
  2780. clear_xks(void)
  2781. {
  2782.     if (nxk) {
  2783.         Free(xk);
  2784.         xk = (struct xks *)NULL;
  2785.         nxk = 0;
  2786.     }
  2787. }
  2788.  
  2789. /*
  2790.  * FieldExit for the 5250-like emulation.
  2791.  * Erases from the current cursor position to the end of the field, and moves
  2792.  * the cursor to the beginning of the next field.
  2793.  *
  2794.  * Derived from work (C) Minolta (Schweiz) AG, Beat Rubischon <bru@minolta.ch>
  2795.  */
  2796. void
  2797. FieldExit_action(Widget w unused, XEvent *event, String *params,
  2798.     Cardinal *num_params)
  2799. {
  2800.     register int    baddr;
  2801.     register unsigned char  *fa;
  2802.  
  2803.     action_debug(FieldExit_action, event, params, num_params);
  2804.     if (IN_ANSI) {
  2805.         net_sendc('\n');
  2806.         return;
  2807.     }
  2808.     if (kybdlock) {
  2809.         enq_ta(FieldExit_action, CN, CN);
  2810.         return;
  2811.     }
  2812.     baddr = cursor_addr;
  2813.     fa = get_field_attribute(baddr);
  2814.     if (FA_IS_PROTECTED(*fa) || IS_FA(screen_buf[baddr])) {
  2815.         operator_error(KL_OERR_PROTECTED);
  2816.         return;
  2817.     }
  2818.     if (formatted) {        /* erase to next field attribute */
  2819.         do {
  2820.             ctlr_add(baddr, CG_null, 0);
  2821.             INC_BA(baddr);
  2822.         } while (!IS_FA(screen_buf[baddr]));
  2823.         mdt_set(fa);
  2824.         cursor_move(next_unprotected(cursor_addr));
  2825.     } else {        /* erase to end of screen */
  2826.         do {
  2827.             ctlr_add(baddr, CG_null, 0);
  2828.             INC_BA(baddr);
  2829.         } while (baddr != 0);
  2830.     }
  2831. }
  2832.  
  2833. #if defined(X3270_DISPLAY) /*[*/
  2834. /*
  2835.  * X-dependent code starts here.
  2836.  */
  2837.  
  2838. /*
  2839.  * Translate a keymap (from an XQueryKeymap or a KeymapNotify event) into
  2840.  * a bitmap of Shift, Meta or Alt keys pressed.
  2841.  */
  2842. #define key_is_down(kc, bitmap) (kc && ((bitmap)[(kc)/8] & (1<<((kc)%8))))
  2843. int
  2844. state_from_keymap(char keymap[32])
  2845. {
  2846.     static Boolean    initted = False;
  2847.     static KeyCode    kc_Shift_L, kc_Shift_R;
  2848.     static KeyCode    kc_Meta_L, kc_Meta_R;
  2849.     static KeyCode    kc_Alt_L, kc_Alt_R;
  2850.     int    pseudo_state = 0;
  2851.  
  2852.     if (!initted) {
  2853.         kc_Shift_L = XKeysymToKeycode(display, XK_Shift_L);
  2854.         kc_Shift_R = XKeysymToKeycode(display, XK_Shift_R);
  2855.         kc_Meta_L  = XKeysymToKeycode(display, XK_Meta_L);
  2856.         kc_Meta_R  = XKeysymToKeycode(display, XK_Meta_R);
  2857.         kc_Alt_L   = XKeysymToKeycode(display, XK_Alt_L);
  2858.         kc_Alt_R   = XKeysymToKeycode(display, XK_Alt_R);
  2859.         initted = True;
  2860.     }
  2861.     if (key_is_down(kc_Shift_L, keymap) ||
  2862.         key_is_down(kc_Shift_R, keymap))
  2863.         pseudo_state |= ShiftKeyDown;
  2864.     if (key_is_down(kc_Meta_L, keymap) ||
  2865.         key_is_down(kc_Meta_R, keymap))
  2866.         pseudo_state |= MetaKeyDown;
  2867.     if (key_is_down(kc_Alt_L, keymap) ||
  2868.         key_is_down(kc_Alt_R, keymap))
  2869.         pseudo_state |= AltKeyDown;
  2870.     return pseudo_state;
  2871. }
  2872. #undef key_is_down
  2873.  
  2874. /*
  2875.  * Process shift keyboard events.  The code has to look for the raw Shift keys,
  2876.  * rather than using the handy "state" field in the event structure.  This is
  2877.  * because the event state is the state _before_ the key was pressed or
  2878.  * released.  This isn't enough information to distinguish between "left
  2879.  * shift released" and "left shift released, right shift still held down"
  2880.  * events, for example.
  2881.  *
  2882.  * This function is also called as part of Focus event processing.
  2883.  */
  2884. void
  2885. PA_Shift_action(Widget w unused, XEvent *event unused, String *params unused,
  2886.     Cardinal *num_params unused)
  2887. {
  2888.     char    keys[32];
  2889.  
  2890. #if defined(INTERNAL_ACTION_DEBUG) /*[*/
  2891.     action_debug(PA_Shift_action, event, params, num_params);
  2892. #endif /*]*/
  2893.     XQueryKeymap(display, keys);
  2894.     shift_event(state_from_keymap(keys));
  2895. }
  2896. #endif /*]*/
  2897.  
  2898. #if defined(X3270_DISPLAY) || defined(C3270) /*[*/
  2899. static Boolean
  2900. build_composites(void)
  2901. {
  2902.     char *cname;
  2903.     char *c, *c0, *c1;
  2904.     char *ln;
  2905.     char ksname[3][64];
  2906.     char junk[2];
  2907.     KeySym k[3];
  2908.     enum keytype a[3];
  2909.     int i;
  2910.     struct composite *cp;
  2911.  
  2912.     if (appres.compose_map == CN) {
  2913.         xs_warning("%s: No %s defined", action_name(Compose_action),
  2914.             ResComposeMap);
  2915.         return False;
  2916.     }
  2917.     cname = xs_buffer("%s.%s", ResComposeMap, appres.compose_map);
  2918.     if ((c0 = get_resource(cname)) == CN) {
  2919.         xs_warning("%s: Cannot find %s \"%s\"",
  2920.             action_name(Compose_action), ResComposeMap,
  2921.             appres.compose_map);
  2922.         return False;
  2923.     }
  2924.     Free(cname);
  2925.     c1 = c = NewString(c0);    /* will be modified by strtok */
  2926.     while ((ln = strtok(c, "\n"))) {
  2927.         Boolean okay = True;
  2928.  
  2929.         c = NULL;
  2930.         if (sscanf(ln, " %63[^+ \t] + %63[^= \t] =%63s%1s",
  2931.             ksname[0], ksname[1], ksname[2], junk) != 3) {
  2932.             xs_warning("%s: Invalid syntax: %s",
  2933.                 action_name(Compose_action), ln);
  2934.             continue;
  2935.         }
  2936.         for (i = 0; i < 3; i++) {
  2937.             k[i] = MyStringToKeysym(ksname[i], &a[i]);
  2938.             if (k[i] == NoSymbol) {
  2939.                 xs_warning("%s: Invalid KeySym: \"%s\"",
  2940.                     action_name(Compose_action), ksname[i]);
  2941.                 okay = False;
  2942.                 break;
  2943.             }
  2944.         }
  2945.         if (!okay)
  2946.             continue;
  2947.         composites = (struct composite *) Realloc((char *)composites,
  2948.             (n_composites + 1) * sizeof(struct composite));
  2949.         cp = composites + n_composites;
  2950.         cp->k1.keysym = k[0];
  2951.         cp->k1.keytype = a[0];
  2952.         cp->k2.keysym = k[1];
  2953.         cp->k2.keytype = a[1];
  2954.         cp->translation.keysym = k[2];
  2955.         cp->translation.keytype = a[2];
  2956.         n_composites++;
  2957.     }
  2958.     Free(c1);
  2959.     return True;
  2960. }
  2961.  
  2962. /*
  2963.  * Called by the toolkit when the "Compose" key is pressed.  "Compose" is
  2964.  * implemented by pressing and releasing three keys: "Compose" and two
  2965.  * data keys.  For example, "Compose" "s" "s" gives the German "ssharp"
  2966.  * character, and "Compose" "C", "," gives a capital "C" with a cedilla
  2967.  * (symbol Ccedilla).
  2968.  *
  2969.  * The mechanism breaks down a little when the user presses "Compose" and
  2970.  * then a non-data key.  Oh well.
  2971.  */
  2972. void
  2973. Compose_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2974. {
  2975.     action_debug(Compose_action, event, params, num_params);
  2976.  
  2977.     if (!composites && !build_composites())
  2978.         return;
  2979.  
  2980.     if (composing == NONE) {
  2981.         composing = COMPOSE;
  2982.         status_compose(True, 0, KT_STD);
  2983.     }
  2984. }
  2985. #endif /*]*/
  2986.  
  2987. #if defined(X3270_DISPLAY) /*[*/
  2988.  
  2989. /*
  2990.  * Called by the toolkit for any key without special actions.
  2991.  */
  2992. void
  2993. Default_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  2994. {
  2995.     XKeyEvent    *kevent = (XKeyEvent *)event;
  2996.     char        buf[32];
  2997.     KeySym        ks;
  2998.     int        ll;
  2999.  
  3000.     action_debug(Default_action, event, params, num_params);
  3001.     switch (event->type) {
  3002.         case KeyPress:
  3003.         ll = XLookupString(kevent, buf, 32, &ks, (XComposeStatus *) 0);
  3004.         if (ll == 1) {
  3005.             /* Remap certain control characters. */
  3006.             switch (buf[0]) {
  3007.                 case '\t':
  3008.                 action_internal(Tab_action, IA_DEFAULT, CN, CN);
  3009.                 break;
  3010.                case '\177':
  3011.                 action_internal(Delete_action, IA_DEFAULT, CN,
  3012.                     CN);
  3013.                 break;
  3014.                 case '\b':
  3015.                 action_internal(BackSpace_action, IA_DEFAULT,
  3016.                     CN, CN);
  3017.                 break;
  3018.                 case '\r':
  3019.                 action_internal(Enter_action, IA_DEFAULT, CN,
  3020.                     CN);
  3021.                 break;
  3022.                 case '\n':
  3023.                 action_internal(Newline_action, IA_DEFAULT, CN,
  3024.                     CN);
  3025.                 break;
  3026.                 default:
  3027.                 key_ACharacter((unsigned char) buf[0], KT_STD,
  3028.                     IA_DEFAULT);
  3029.             }
  3030.             return;
  3031.         }
  3032.  
  3033.         /* Pick some other reasonable defaults. */
  3034.         switch (ks) {
  3035.             case XK_Up:
  3036.             action_internal(Up_action, IA_DEFAULT, CN, CN);
  3037.             break;
  3038.             case XK_Down:
  3039.             action_internal(Down_action, IA_DEFAULT, CN, CN);
  3040.             break;
  3041.             case XK_Left:
  3042.             action_internal(Left_action, IA_DEFAULT, CN, CN);
  3043.             break;
  3044.             case XK_Right:
  3045.             action_internal(Right_action, IA_DEFAULT, CN, CN);
  3046.             break;
  3047.             case XK_Insert:
  3048. #if defined(XK_KP_Insert) /*[*/
  3049.             case XK_KP_Insert:
  3050. #endif /*]*/
  3051.             action_internal(Insert_action, IA_DEFAULT, CN, CN);
  3052.             break;
  3053.             case XK_Delete:
  3054.             action_internal(Delete_action, IA_DEFAULT, CN, CN);
  3055.             break;
  3056.             case XK_Home:
  3057.             action_internal(Home_action, IA_DEFAULT, CN, CN);
  3058.             break;
  3059.             case XK_Tab:
  3060.             action_internal(Tab_action, IA_DEFAULT, CN, CN);
  3061.             break;
  3062.             case XK_Clear:
  3063.             action_internal(Clear_action, IA_DEFAULT, CN, CN);
  3064.             break;
  3065.             case XK_Sys_Req:
  3066.             action_internal(SysReq_action, IA_DEFAULT, CN, CN);
  3067.             break;
  3068.  
  3069. #if defined(XK_3270_Duplicate) /*[*/
  3070.             /* Funky 3270 keysyms. */
  3071.             case XK_3270_Duplicate:
  3072.             action_internal(Dup_action, IA_DEFAULT, CN, CN);
  3073.             break;
  3074.             case XK_3270_FieldMark:
  3075.             action_internal(FieldMark_action, IA_DEFAULT, CN, CN);
  3076.             break;
  3077.             case XK_3270_Right2:
  3078.             action_internal(Right2_action, IA_DEFAULT, CN, CN);
  3079.             break;
  3080.             case XK_3270_Left2:
  3081.             action_internal(Left2_action, IA_DEFAULT, CN, CN);
  3082.             break;
  3083.             case XK_3270_BackTab:
  3084.             action_internal(BackTab_action, IA_DEFAULT, CN, CN);
  3085.             break;
  3086.             case XK_3270_EraseEOF:
  3087.             action_internal(EraseEOF_action, IA_DEFAULT, CN, CN);
  3088.             break;
  3089.             case XK_3270_EraseInput:
  3090.             action_internal(EraseInput_action, IA_DEFAULT, CN, CN);
  3091.             break;
  3092.             case XK_3270_Reset:
  3093.             action_internal(Reset_action, IA_DEFAULT, CN, CN);
  3094.             break;
  3095.             case XK_3270_PA1:
  3096.             action_internal(PA_action, IA_DEFAULT, "1", CN);
  3097.             break;
  3098.             case XK_3270_PA2:
  3099.             action_internal(PA_action, IA_DEFAULT, "2", CN);
  3100.             break;
  3101.             case XK_3270_PA3:
  3102.             action_internal(PA_action, IA_DEFAULT, "3", CN);
  3103.             break;
  3104.             case XK_3270_Attn:
  3105.             action_internal(Attn_action, IA_DEFAULT, CN, CN);
  3106.             break;
  3107.             case XK_3270_AltCursor:
  3108.             action_internal(AltCursor_action, IA_DEFAULT, CN, CN);
  3109.             break;
  3110.             case XK_3270_CursorSelect:
  3111.             action_internal(CursorSelect_action, IA_DEFAULT, CN,
  3112.                 CN);
  3113.             break;
  3114.             case XK_3270_Enter:
  3115.             action_internal(Enter_action, IA_DEFAULT, CN, CN);
  3116.             break;
  3117. #endif /*]*/
  3118.  
  3119. #if defined(X3270_APL) /*[*/
  3120.             /* Funky APL keysyms. */
  3121.             case XK_downcaret:
  3122.             action_internal(Key_action, IA_DEFAULT, "apl_downcaret",
  3123.                 CN);
  3124.             break;
  3125.             case XK_upcaret:
  3126.             action_internal(Key_action, IA_DEFAULT, "apl_upcaret",
  3127.                 CN);
  3128.             break;
  3129.             case XK_overbar:
  3130.             action_internal(Key_action, IA_DEFAULT, "apl_overbar",
  3131.                 CN);
  3132.             break;
  3133.             case XK_downtack:
  3134.             action_internal(Key_action, IA_DEFAULT, "apl_downtack",
  3135.                 CN);
  3136.             break;
  3137.             case XK_upshoe:
  3138.             action_internal(Key_action, IA_DEFAULT, "apl_upshoe",
  3139.                 CN);
  3140.             break;
  3141.             case XK_downstile:
  3142.             action_internal(Key_action, IA_DEFAULT, "apl_downstile",
  3143.                 CN);
  3144.             break;
  3145.             case XK_underbar:
  3146.             action_internal(Key_action, IA_DEFAULT, "apl_underbar",
  3147.                 CN);
  3148.             break;
  3149.             case XK_jot:
  3150.             action_internal(Key_action, IA_DEFAULT, "apl_jot", CN);
  3151.             break;
  3152.             case XK_quad:
  3153.             action_internal(Key_action, IA_DEFAULT, "apl_quad", CN);
  3154.             break;
  3155.             case XK_uptack:
  3156.             action_internal(Key_action, IA_DEFAULT, "apl_uptack",
  3157.                 CN);
  3158.             break;
  3159.             case XK_circle:
  3160.             action_internal(Key_action, IA_DEFAULT, "apl_circle",
  3161.                 CN);
  3162.             break;
  3163.             case XK_upstile:
  3164.             action_internal(Key_action, IA_DEFAULT, "apl_upstile",
  3165.                 CN);
  3166.             break;
  3167.             case XK_downshoe:
  3168.             action_internal(Key_action, IA_DEFAULT, "apl_downshoe",
  3169.                 CN);
  3170.             break;
  3171.             case XK_rightshoe:
  3172.             action_internal(Key_action, IA_DEFAULT, "apl_rightshoe",
  3173.                 CN);
  3174.             break;
  3175.             case XK_leftshoe:
  3176.             action_internal(Key_action, IA_DEFAULT, "apl_leftshoe",
  3177.                 CN);
  3178.             break;
  3179.             case XK_lefttack:
  3180.             action_internal(Key_action, IA_DEFAULT, "apl_lefttack",
  3181.                 CN);
  3182.             break;
  3183.             case XK_righttack:
  3184.             action_internal(Key_action, IA_DEFAULT, "apl_righttack",
  3185.                 CN);
  3186.             break;
  3187. #endif /*]*/
  3188.  
  3189.             default:
  3190.             if (ks >= XK_F1 && ks <= XK_F24) {
  3191.                 (void) sprintf(buf, "%ld", ks - XK_F1 + 1);
  3192.                 action_internal(PF_action, IA_DEFAULT, buf, CN);
  3193.             } else
  3194.                 trace_event(" %s: dropped (unknown keysym)\n",
  3195.                     action_name(Default_action));
  3196.             break;
  3197.         }
  3198.         break;
  3199.  
  3200.         case ButtonPress:
  3201.         case ButtonRelease:
  3202.         trace_event(" %s: dropped (no action configured)\n",
  3203.             action_name(Default_action));
  3204.         break;
  3205.         default:
  3206.         trace_event(" %s: dropped (unknown event type)\n",
  3207.             action_name(Default_action));
  3208.         break;
  3209.     }
  3210. }
  3211.  
  3212. /*
  3213.  * Set or clear a temporary keymap.
  3214.  *
  3215.  *   TemporaryKeymap(x)        toggle keymap "x" (add "x" to the keymap, or if
  3216.  *                "x" was already added, remove it)
  3217.  *   TemporaryKeymap()        removes the previous keymap, if any
  3218.  *   TemporaryKeymap(None)    removes the previous keymap, if any
  3219.  */
  3220. void
  3221. TemporaryKeymap_action(Widget w unused, XEvent *event, String *params, Cardinal *num_params)
  3222. {
  3223.     action_debug(TemporaryKeymap_action, event, params, num_params);
  3224.  
  3225.     if (check_usage(TemporaryKeymap_action, *num_params, 0, 1) < 0)
  3226.         return;
  3227.  
  3228.     if (*num_params == 0 || !strcmp(params[0], "None")) {
  3229.         (void) temporary_keymap(CN);
  3230.         return;
  3231.     }
  3232.  
  3233.     if (temporary_keymap(params[0]) < 0)
  3234.         popup_an_error("%s: Can't find %s %s",
  3235.             action_name(TemporaryKeymap_action), ResKeymap, params[0]);
  3236. }
  3237.  
  3238. #endif /*]*/
  3239.